diff --git a/ephios/core/forms/events.py b/ephios/core/forms/events.py index 05627cb80..78f8c8964 100644 --- a/ephios/core/forms/events.py +++ b/ephios/core/forms/events.py @@ -1,6 +1,6 @@ import operator import re -from datetime import date, datetime, timedelta +from datetime import datetime, timedelta from crispy_forms.bootstrap import FormActions from crispy_forms.helper import FormHelper @@ -16,7 +16,6 @@ from django_select2.forms import Select2MultipleWidget from dynamic_preferences.forms import PreferenceForm from guardian.shortcuts import assign_perm, get_objects_for_user, get_users_with_perms, remove_perm -from recurrence.forms import RecurrenceField from ephios.core.dynamic_preferences_registry import event_type_preference_registry from ephios.core.models import Event, EventType, LocalParticipation, Shift, UserProfile @@ -26,7 +25,7 @@ from ephios.extra.colors import clear_eventtype_color_css_fragment_cache from ephios.extra.crispy import AbortLink from ephios.extra.permissions import get_groups_with_perms -from ephios.extra.widgets import ColorInput, CustomDateInput, CustomTimeInput +from ephios.extra.widgets import ColorInput, CustomDateInput, CustomTimeInput, RecurrenceField from ephios.modellogging.log import add_log_recorder, update_log from ephios.modellogging.recorders import ( DerivedFieldsLogRecorder, @@ -238,16 +237,12 @@ def clean(self): return cleaned_data -class EventDuplicationForm(forms.Form): - start_date = forms.DateField( - widget=CustomDateInput, - initial=date.today(), - help_text=_( - "This date will be used as the start date for recurring events that you create below, e.g. daily events will be created from this date onwards." - ), - label=_("Start date"), - ) - recurrence = RecurrenceField(required=False) +class EventCopyForm(forms.Form): + recurrence = RecurrenceField() + + +class ShiftCopyForm(forms.Form): + recurrence = RecurrenceField(pick_hour=True) class EventTypeForm(forms.ModelForm): diff --git a/ephios/core/templates/core/event_copy.html b/ephios/core/templates/core/event_copy.html index e93c1554e..b4a446021 100644 --- a/ephios/core/templates/core/event_copy.html +++ b/ephios/core/templates/core/event_copy.html @@ -8,51 +8,17 @@ {% endblock %} {% block css %} - {% endblock %} -{% block javascript %} - - - -{% endblock %} - -{% block html_head %} - -{% endblock %} - - {% block content %} - -
-
- {% csrf_token %} - -
-
- {{ form.start_date|as_crispy_field }} - {{ form.recurrence }} -
-
-

-
-
-
- -
- {% translate "Back" %} - - -
- -
-
+ {{ form.errors }} +
+ {% csrf_token %} + {{ form.recurrence }} +
{% endblock %} - diff --git a/ephios/core/templates/core/fragments/shift_header.html b/ephios/core/templates/core/fragments/shift_header.html index f6888e2a6..acb43d793 100644 --- a/ephios/core/templates/core/fragments/shift_header.html +++ b/ephios/core/templates/core/fragments/shift_header.html @@ -57,6 +57,9 @@
  • {% translate "Edit" %}
  • +
  • + {% translate "Copy" %}
  • {% if shift.event.shifts.count > 1 %} {% translate "Delete" %} diff --git a/ephios/core/templates/core/shift_copy.html b/ephios/core/templates/core/shift_copy.html new file mode 100644 index 000000000..fc8a5ac8a --- /dev/null +++ b/ephios/core/templates/core/shift_copy.html @@ -0,0 +1,24 @@ +{% extends "base.html" %} +{% load crispy_forms_filters %} +{% load static %} +{% load i18n %} + +{% block title %} + {% translate "Copy shift" %} +{% endblock %} + +{% block css %} +{% endblock %} + +{% block content %} + + {{ form.errors }} +
    + {% csrf_token %} + {{ form.recurrence }} +
    +{% endblock %} diff --git a/ephios/core/templates/core/shift_form.html b/ephios/core/templates/core/shift_form.html index 307e933cc..824b8ed60 100644 --- a/ephios/core/templates/core/shift_form.html +++ b/ephios/core/templates/core/shift_form.html @@ -80,6 +80,9 @@

    + diff --git a/ephios/core/urls.py b/ephios/core/urls.py index e4eb61211..411956db6 100644 --- a/ephios/core/urls.py +++ b/ephios/core/urls.py @@ -41,7 +41,7 @@ EventNotificationView, EventUpdateView, HomeView, - RRuleOccurrenceView, + ShiftCopyView, ) from ephios.core.views.eventtype import ( EventTypeCreateView, @@ -177,12 +177,8 @@ AddPlaceholderParticipantView.as_view(), name="shift_disposition_add_placeholder", ), + path("shifts//copy/", ShiftCopyView.as_view(), name="shift_copy"), path("calendar//", user_event_feed_view, name="user_event_feed"), - path( - "extra/rruleoccurrence/", - RRuleOccurrenceView.as_view(), - name="rrule_occurrences", - ), path("settings/data/", PersonalDataSettingsView.as_view(), name="settings_personal_data"), path("settings/calendar/", CalendarSettingsView.as_view(), name="settings_calendar"), path( diff --git a/ephios/core/views/event.py b/ephios/core/views/event.py index 4c3223047..68f18b6ce 100644 --- a/ephios/core/views/event.py +++ b/ephios/core/views/event.py @@ -1,20 +1,19 @@ -import json from calendar import _nextmonth, _prevmonth from collections import defaultdict +from copy import copy from datetime import datetime, time, timedelta +from csp.decorators import csp_exempt from django import forms from django.conf import settings from django.contrib import messages from django.contrib.auth.mixins import LoginRequiredMixin from django.core.exceptions import ValidationError from django.db.models import BooleanField, Case, Count, Max, Min, Prefetch, Q, QuerySet, When -from django.http import HttpResponse from django.shortcuts import get_object_or_404, redirect from django.urls import reverse, reverse_lazy from django.utils import timezone from django.utils.datastructures import MultiValueDict -from django.utils.formats import date_format from django.utils.functional import cached_property from django.utils.safestring import mark_safe from django.utils.timezone import get_current_timezone, make_aware @@ -32,10 +31,9 @@ ) from django.views.generic.detail import SingleObjectMixin from guardian.shortcuts import assign_perm, get_objects_for_user, get_users_with_perms -from recurrence.forms import RecurrenceField from ephios.core.calendar import ShiftCalendar -from ephios.core.forms.events import EventDuplicationForm, EventForm, EventNotificationForm +from ephios.core.forms.events import EventCopyForm, EventForm, EventNotificationForm, ShiftCopyForm from ephios.core.models import AbstractParticipation, Event, EventType, Shift from ephios.core.services.notifications.types import ( CustomEventParticipantNotification, @@ -536,23 +534,18 @@ class EventCopyView(CustomPermissionRequiredMixin, SingleObjectMixin, FormView): permission_required = "core.add_event" model = Event template_name = "core/event_copy.html" - form_class = EventDuplicationForm + form_class = EventCopyForm def setup(self, request, *args, **kwargs): super().setup(request, *args, **kwargs) self.object = self.get_object() + def get_success_url(self): + return reverse("core:event_copy", kwargs={"pk": self.object.pk}) + def form_valid(self, form): tz = get_current_timezone() - occurrences = form.cleaned_data["recurrence"].between( - datetime.now() - timedelta(days=1), - datetime.now() + timedelta(days=7305), # allow dates up to twenty years in the future - inc=True, - dtstart=datetime.combine( - forms.DateField().to_python(self.request.POST["start_date"]), datetime.min.time() - ), - ) - for date in occurrences: + for date in form.cleaned_data["recurrence"].xafter(timezone.now(), 1000, inc=True): event = self.get_object() start_date = event.get_start_time().astimezone(tz).date() shifts = list(event.shifts.all()) @@ -609,30 +602,43 @@ def form_valid(self, form): messages.success(self.request, _("Event copied successfully.")) return redirect(reverse("core:event_list")) + @classmethod + def as_view(cls, **initkwargs): + return csp_exempt(super().as_view(**initkwargs)) -class RRuleOccurrenceView(CustomPermissionRequiredMixin, View): - permission_required = "core.add_event" - def post(self, *args, **kwargs): - try: - recurrence = RecurrenceField().clean(self.request.POST["recurrence_string"]) - return HttpResponse( - json.dumps( - recurrence.between( - datetime.now() - timedelta(days=1), - datetime.now() - + timedelta(days=7305), # allow dates up to twenty years in the future - inc=True, - dtstart=datetime.combine( - forms.DateField().to_python(self.request.POST["dtstart"]), - datetime.min.time(), - ), - ), - default=lambda obj: date_format(obj, format="SHORT_DATE_FORMAT"), - ) - ) - except (TypeError, KeyError, ValidationError): - return HttpResponse() +class ShiftCopyView(CustomPermissionRequiredMixin, SingleObjectMixin, FormView): + permission_required = "core.change_event" + model = Shift + template_name = "core/shift_copy.html" + form_class = ShiftCopyForm + + def setup(self, request, *args, **kwargs): + super().setup(request, *args, **kwargs) + self.object = self.get_object() + + def get_success_url(self): + return reverse("core:event_detail", kwargs={"pk": self.object.event.pk, "slug": "event"}) + + def form_valid(self, form): + shift = self.object + duration = shift.end_time - shift.start_time + meeting_offset = shift.start_time - shift.meeting_time + shifts_to_create = [] + for dt in form.cleaned_data["recurrence"].xafter(timezone.now(), 1000, inc=True): + shift = copy(shift) + shift.pk = None + shift.meeting_time = dt - meeting_offset + shift.start_time = dt + shift.end_time = dt + duration + shifts_to_create.append(shift) + Shift.objects.bulk_create(shifts_to_create) + messages.success(self.request, _("Shift copied successfully.")) + return super().form_valid(form) + + @classmethod + def as_view(cls, **initkwargs): + return csp_exempt(super().as_view(**initkwargs)) class HomeView(LoginRequiredMixin, TemplateView): diff --git a/ephios/core/views/shift.py b/ephios/core/views/shift.py index 0df102991..1dfe4bbba 100644 --- a/ephios/core/views/shift.py +++ b/ephios/core/views/shift.py @@ -108,6 +108,8 @@ def post(self, *args, **kwargs): self.save_plugin_forms() if "addAnother" in self.request.POST: return redirect(reverse("core:event_createshift", kwargs={"pk": self.kwargs.get("pk")})) + if "copyShift" in self.request.POST: + return redirect(reverse("core:shift_copy", kwargs={"pk": shift.pk})) try: self.event.activate() messages.success( @@ -232,6 +234,8 @@ def post(self, *args, **kwargs): return redirect( reverse("core:event_createshift", kwargs={"pk": shift.event.pk}) ) + if "copyShift" in self.request.POST: + return redirect(reverse("core:shift_copy", kwargs={"pk": shift.pk})) messages.success( self.request, _("The shift {shift} has been saved.").format(shift=shift) ) diff --git a/ephios/extra/templates/extra/widgets/recurrence_picker.html b/ephios/extra/templates/extra/widgets/recurrence_picker.html new file mode 100644 index 000000000..744b9bc56 --- /dev/null +++ b/ephios/extra/templates/extra/widgets/recurrence_picker.html @@ -0,0 +1,231 @@ +{% load i18n %} +{% load static %} + + +
    +
    +
    +
    {% translate "starting at" %}
    + + +
    +
      +
    • +
      +
      + + + + + +
      +
      + +
      +
      + +
      + {% translate "Repeat every" %} +
      + +
      + [[ frequency_strings[rule.freq] ]] + {% translate "on" %} +
      + +
      +
      + + +
      +
      + +
      +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      +
      + +
      +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      +
      + +
      +
      +
      + +
      + + {% translate "until" %} + +
      + +
      +
      + +
      + +
      + +
      +
      + +
      + + {% translate "for" %} + +
      + +
      + + {% translate "ocurrences" %} + +
      +
      +
    • +
    • +
      +
      + +
      +
      + +
      +
      + +
      +
      +
    • +
    +
    + + + +
    + + {{ csrf_token }} +
    +
    +

    {% translate "Selected dates:" %}

    +
    +
      +
    • [[ date ]]
    • +
    +
    +
    +
    + + diff --git a/ephios/extra/widgets.py b/ephios/extra/widgets.py index 729d45369..5eba660ef 100644 --- a/ephios/extra/widgets.py +++ b/ephios/extra/widgets.py @@ -1,6 +1,9 @@ -from django.forms import DateInput, MultiWidget, TimeInput +from dateutil.rrule import rrulestr +from django.core.exceptions import ValidationError +from django.forms import CharField, DateInput, MultiWidget, Textarea, TimeInput from django.forms.utils import to_current_timezone from django.forms.widgets import Input +from django.utils.translation import gettext as _ class CustomDateInput(DateInput): @@ -40,3 +43,30 @@ def decompress(self, value): class ColorInput(Input): input_type = "color" + + +class RecurrenceWidget(Textarea): + template_name = "extra/widgets/recurrence_picker.html" + + def __init__(self, *args, **kwargs): + self.pick_hour = kwargs.pop("pick_hour", False) + super().__init__(*args, **kwargs) + + def get_context(self, name, value, attrs): + context = super().get_context(name, value, attrs) + context["widget"]["pick_hour"] = self.pick_hour + return context + + +class RecurrenceField(CharField): + widget = RecurrenceWidget + + def __init__(self, *args, pick_hour=False, **kwargs): + self.widget = RecurrenceWidget(pick_hour=pick_hour) + super().__init__(*args, **kwargs) + + def clean(self, value): + try: + return rrulestr(value) + except (TypeError, KeyError, ValueError) as e: + raise ValidationError(_("Invalid recurrence rule: {error}").format(error=e)) from e diff --git a/ephios/static/ephios/js/event_copy.js b/ephios/static/ephios/js/event_copy.js index e20fd4b2d..f8bde71b7 100644 --- a/ephios/static/ephios/js/event_copy.js +++ b/ephios/static/ephios/js/event_copy.js @@ -1,27 +1,145 @@ -$(document).ready(function () { - $("#btn_check").on('click', function () { - $.ajax({ - url: JSON.parse(document.getElementById('rrule_url').textContent).url, - type: 'POST', - data: {"recurrence_string": $("#id_recurrence").val(), "dtstart": $("#id_start_date").val()}, - headers: {"X-CSRFToken": getCookie("csrftoken")}, - - success: function (data) { - $("#rrule_occurrences_heading").html(gettext("Currently selected dates")); - if (data) { - data = JSON.parse(data) - if (Array.isArray(data) && data.length) { - $('#rrule_occurrences').html(data.join("
    ")); - return; - } +const {createApp, ref, computed} = Vue + +function formatDate(date_obj, sep = "-") { + let month = date_obj.getMonth() + 1; + let day = date_obj.getDate(); + return date_obj.getFullYear() + sep + (month < 10 ? "0" : "") + month + sep + (day < 10 ? "0" : "") + day +} + +function formatHourOrZero(time_string, pickHour=false) { + if (time_string && pickHour) { + return [time_string.slice(0,2), time_string.slice(3,5), 0] + } + return [0, 0, 0] +} + +document.addEventListener('DOMContentLoaded', (event) => { + createApp({ + setup() { + const pickHour = JSON.parse(document.getElementById("pick_hour").value); + const DTSTART = ref(formatDate(new Date())) + const DTSTART_TIME = ref("00:00") + const rules = ref([]) + const dates = ref([]) + const weekdays = [gettext("Monday"), gettext("Tuesday"), gettext("Wednesday"), gettext("Thursday"), gettext("Friday"), gettext("Saturday"), gettext("Sunday")] + const frequency_strings = [gettext("year"), gettext("month"), gettext("week"), gettext("day")] + const frequencies = rrule.Frequency + const months = [{id: 1, short: "Jan", long: "January"}, {id: 2, short: "Feb", long: "February"}, { + id: 3, short: "Mar", long: "March" + }, {id: 4, short: "Apr", long: "April"}, {id: 5, short: "May", long: "May"}, { + id: 6, short: "Jun", long: "June" + }, {id: 7, short: "Jul", long: "July"}, {id: 8, short: "Aug", long: "August"}, { + id: 9, short: "Sep", long: "September" + }, {id: 10, short: "Oct", long: "October"}, {id: 11, short: "Nov", long: "November"}, { + id: 12, short: "Dec", long: "December" + }] + + async function addRule() { + rules.value.push({freq: rrule.RRule.WEEKLY, interval: 1, byweekday: []}) + } + + async function removeRule(rule) { + rules.value.splice(rules.value.indexOf(rule), 1) + } + + async function addDate() { + dates.value.push({date: "", time: ""}); + } + + async function removeDate(date) { + dates.value.splice(dates.value.indexOf(date), 1) + } + + async function changeFreq(rule, freq){ + rule.freq = freq + rule.byweekday = [] + delete rule.bymonthday + delete rule.bymonth + delete rule.bysetpos + delete rule.month_mode + } + + function submitForm(event) { + event.target.submit(); + } + + function isRuleValid(rule) { + let isValid = true + switch (rule.freq) { + case frequencies.WEEKLY: + isValid = isValid && rule.byweekday && rule.byweekday.length > 0 + break + case frequencies.MONTHLY: + isValid = isValid && (rule.month_mode === "bymonthday" && rule.bymonthday || rule.month_mode === "bysetpos" && rule.bysetpos && rule.byweekday) + break + case frequencies.YEARLY: + isValid = isValid && (rule.year_mode === "bymonthday" && rule.bymonthday && rule.bymonth || rule.year_mode === "bysetpos" && rule.bysetpos && rule.byweekday && rule.bymonth) + break } - $('#rrule_occurrences').html("

    " + gettext("No dates selected") + "

    "); + + // end date set + isValid = isValid && (rule.end_mode === "COUNT" && rule.count || rule.end_mode === "UNTIL" && rule.until) + + return isValid } - }); - }); -}); -function parseIsoDatetime(dtstr) { - var dt = dtstr.split(/[: T-]/).map(parseFloat); - return new Date(dt[0], dt[1] - 1, dt[2], dt[3] || 0, dt[4] || 0, dt[5] || 0, 0); -} + const rrule_set = computed(() => { + let set = new rrule.RRuleSet() + rules.value.forEach(rule => { + if (!isRuleValid(rule)) { + return + } + set.rrule(new rrule.RRule({ + freq: rule.freq, + interval: rule.interval, + dtstart: rrule.datetime(...DTSTART.value.split("-"), ...formatHourOrZero(DTSTART_TIME.value, pickHour)), + byweekday: rule.byweekday, + bymonthday: rule.month_mode === "bymonthday" ? rule.bymonthday : undefined, + bysetpos: rule.month_mode === "bysetpos" ? rule.bysetpos : undefined, + bymonth: rule.bymonth, + count: rule.end_mode === "COUNT" ? rule.count : undefined, + until: rule.end_mode === "UNTIL" && rule.until ? rrule.datetime(...rule.until.split("-"), formatHourOrZero(rule.UNTIL_TIME, pickHour)) : undefined, + tzid: Intl.DateTimeFormat().resolvedOptions().timeZone, + })) + }) + dates.value.forEach(date => { + if (date.date && (!pickHour || date.time)) { + set.rdate(rrule.datetime(...date.date.split("-"), ...formatHourOrZero(date.time, pickHour))) + } + }) + return set + }) + + const computed_dates = computed(() => { + return rrule_set ? rrule_set.value.all().map(date => { + return formatDate(date) + " " + (date.getUTCHours() < 10 ? "0" : "") + date.getUTCHours() + ":" + (date.getUTCMinutes() < 10 ? "0" : "") + date.getUTCMinutes() + }): [] + }) + + const rrule_string = computed(() => { + return rrule_set ? rrule_set.value.toString() : "" + }) + + return { + rules, + DTSTART, + DTSTART_TIME, + addRule, + removeRule, + addDate, + removeDate, + submitForm, + rrule_string, + weekdays, + months, + dates, + computed_dates, + pickHour, + frequencies, + frequency_strings, + changeFreq, + isRuleValid, + } + }, delimiters: ['[[', ']]'] + }).mount('#vue_app'); +}); diff --git a/ephios/static/ephios/js/main.js b/ephios/static/ephios/js/main.js index 8935114ab..789131604 100644 --- a/ephios/static/ephios/js/main.js +++ b/ephios/static/ephios/js/main.js @@ -95,11 +95,6 @@ $(document).ready(function () { // Configure all prerendered Forms handleForms($(document)); - var recurrenceFields = document.querySelectorAll('.recurrence-widget'); - Array.prototype.forEach.call(recurrenceFields, function (field, index) { - new recurrence.widget.Widget(field.id, {}); - }); - $('#checkall').change(function () { $('.cb-element').prop('checked', this.checked); }); diff --git a/ephios/static/rrule/rrule.js b/ephios/static/rrule/rrule.js new file mode 100644 index 000000000..85b2446b9 --- /dev/null +++ b/ephios/static/rrule/rrule.js @@ -0,0 +1,3803 @@ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define([], factory); + else if(typeof exports === 'object') + exports["rrule"] = factory(); + else + root["rrule"] = factory(); +})(typeof self !== 'undefined' ? self : this, () => { +return /******/ (() => { // webpackBootstrap +/******/ "use strict"; +/******/ // The require scope +/******/ var __webpack_require__ = {}; +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/define property getters */ +/******/ (() => { +/******/ // define getter functions for harmony exports +/******/ __webpack_require__.d = (exports, definition) => { +/******/ for(var key in definition) { +/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { +/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); +/******/ } +/******/ } +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/make namespace object */ +/******/ (() => { +/******/ // define __esModule on exports +/******/ __webpack_require__.r = (exports) => { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +// ESM COMPAT FLAG +__webpack_require__.r(__webpack_exports__); + +// EXPORTS +__webpack_require__.d(__webpack_exports__, { + "ALL_WEEKDAYS": () => (/* reexport */ ALL_WEEKDAYS), + "Frequency": () => (/* reexport */ Frequency), + "RRule": () => (/* reexport */ RRule), + "RRuleSet": () => (/* reexport */ RRuleSet), + "Weekday": () => (/* reexport */ Weekday), + "datetime": () => (/* reexport */ datetime), + "rrulestr": () => (/* reexport */ rrulestr) +}); + +;// CONCATENATED MODULE: ./src/weekday.ts +// ============================================================================= +// Weekday +// ============================================================================= +var ALL_WEEKDAYS = [ + 'MO', + 'TU', + 'WE', + 'TH', + 'FR', + 'SA', + 'SU', +]; +var Weekday = /** @class */ (function () { + function Weekday(weekday, n) { + if (n === 0) + throw new Error("Can't create weekday with n == 0"); + this.weekday = weekday; + this.n = n; + } + Weekday.fromStr = function (str) { + return new Weekday(ALL_WEEKDAYS.indexOf(str)); + }; + // __call__ - Cannot call the object directly, do it through + // e.g. RRule.TH.nth(-1) instead, + Weekday.prototype.nth = function (n) { + return this.n === n ? this : new Weekday(this.weekday, n); + }; + // __eq__ + Weekday.prototype.equals = function (other) { + return this.weekday === other.weekday && this.n === other.n; + }; + // __repr__ + Weekday.prototype.toString = function () { + var s = ALL_WEEKDAYS[this.weekday]; + if (this.n) + s = (this.n > 0 ? '+' : '') + String(this.n) + s; + return s; + }; + Weekday.prototype.getJsWeekday = function () { + return this.weekday === 6 ? 0 : this.weekday + 1; + }; + return Weekday; +}()); + + +;// CONCATENATED MODULE: ./src/helpers.ts +// ============================================================================= +// Helper functions +// ============================================================================= + +var isPresent = function (value) { + return value !== null && value !== undefined; +}; +var isNumber = function (value) { + return typeof value === 'number'; +}; +var isWeekdayStr = function (value) { + return typeof value === 'string' && ALL_WEEKDAYS.includes(value); +}; +var isArray = Array.isArray; +/** + * Simplified version of python's range() + */ +var range = function (start, end) { + if (end === void 0) { end = start; } + if (arguments.length === 1) { + end = start; + start = 0; + } + var rang = []; + for (var i = start; i < end; i++) + rang.push(i); + return rang; +}; +var clone = function (array) { + return [].concat(array); +}; +var repeat = function (value, times) { + var i = 0; + var array = []; + if (isArray(value)) { + for (; i < times; i++) + array[i] = [].concat(value); + } + else { + for (; i < times; i++) + array[i] = value; + } + return array; +}; +var toArray = function (item) { + if (isArray(item)) { + return item; + } + return [item]; +}; +function padStart(item, targetLength, padString) { + if (padString === void 0) { padString = ' '; } + var str = String(item); + targetLength = targetLength >> 0; + if (str.length > targetLength) { + return String(str); + } + targetLength = targetLength - str.length; + if (targetLength > padString.length) { + padString += repeat(padString, targetLength / padString.length); + } + return padString.slice(0, targetLength) + String(str); +} +/** + * Python like split + */ +var split = function (str, sep, num) { + var splits = str.split(sep); + return num + ? splits.slice(0, num).concat([splits.slice(num).join(sep)]) + : splits; +}; +/** + * closure/goog/math/math.js:modulo + * Copyright 2006 The Closure Library Authors. + * The % operator in JavaScript returns the remainder of a / b, but differs from + * some other languages in that the result will have the same sign as the + * dividend. For example, -1 % 8 == -1, whereas in some other languages + * (such as Python) the result would be 7. This function emulates the more + * correct modulo behavior, which is useful for certain applications such as + * calculating an offset index in a circular list. + * + * @param {number} a The dividend. + * @param {number} b The divisor. + * @return {number} a % b where the result is between 0 and b (either 0 <= x < b + * or b < x <= 0, depending on the sign of b). + */ +var pymod = function (a, b) { + var r = a % b; + // If r and b differ in sign, add b to wrap the result to the correct sign. + return r * b < 0 ? r + b : r; +}; +/** + * @see: + */ +var divmod = function (a, b) { + return { div: Math.floor(a / b), mod: pymod(a, b) }; +}; +var empty = function (obj) { + return !isPresent(obj) || obj.length === 0; +}; +/** + * Python-like boolean + * + * @return {Boolean} value of an object/primitive, taking into account + * the fact that in Python an empty list's/tuple's + * boolean value is False, whereas in JS it's true + */ +var notEmpty = function (obj) { + return !empty(obj); +}; +/** + * Return true if a value is in an array + */ +var includes = function (arr, val) { + return notEmpty(arr) && arr.indexOf(val) !== -1; +}; + +;// CONCATENATED MODULE: ./src/dateutil.ts + +var datetime = function (y, m, d, h, i, s) { + if (h === void 0) { h = 0; } + if (i === void 0) { i = 0; } + if (s === void 0) { s = 0; } + return new Date(Date.UTC(y, m - 1, d, h, i, s)); +}; +/** + * General date-related utilities. + * Also handles several incompatibilities between JavaScript and Python + * + */ +var MONTH_DAYS = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; +/** + * Number of milliseconds of one day + */ +var ONE_DAY = 1000 * 60 * 60 * 24; +/** + * @see: + */ +var MAXYEAR = 9999; +/** + * Python uses 1-Jan-1 as the base for calculating ordinals but we don't + * want to confuse the JS engine with milliseconds > Number.MAX_NUMBER, + * therefore we use 1-Jan-1970 instead + */ +var ORDINAL_BASE = datetime(1970, 1, 1); +/** + * Python: MO-SU: 0 - 6 + * JS: SU-SAT 0 - 6 + */ +var PY_WEEKDAYS = [6, 0, 1, 2, 3, 4, 5]; +/** + * py_date.timetuple()[7] + */ +var getYearDay = function (date) { + var dateNoTime = new Date(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()); + return (Math.ceil((dateNoTime.valueOf() - new Date(date.getUTCFullYear(), 0, 1).valueOf()) / + ONE_DAY) + 1); +}; +var isLeapYear = function (year) { + return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; +}; +var isDate = function (value) { + return value instanceof Date; +}; +var isValidDate = function (value) { + return isDate(value) && !isNaN(value.getTime()); +}; +/** + * @return {Number} the date's timezone offset in ms + */ +var tzOffset = function (date) { + return date.getTimezoneOffset() * 60 * 1000; +}; +/** + * @see: + */ +var daysBetween = function (date1, date2) { + // The number of milliseconds in one day + // Convert both dates to milliseconds + var date1ms = date1.getTime(); + var date2ms = date2.getTime(); + // Calculate the difference in milliseconds + var differencems = date1ms - date2ms; + // Convert back to days and return + return Math.round(differencems / ONE_DAY); +}; +/** + * @see: + */ +var toOrdinal = function (date) { + return daysBetween(date, ORDINAL_BASE); +}; +/** + * @see - + */ +var fromOrdinal = function (ordinal) { + return new Date(ORDINAL_BASE.getTime() + ordinal * ONE_DAY); +}; +var getMonthDays = function (date) { + var month = date.getUTCMonth(); + return month === 1 && isLeapYear(date.getUTCFullYear()) + ? 29 + : MONTH_DAYS[month]; +}; +/** + * @return {Number} python-like weekday + */ +var getWeekday = function (date) { + return PY_WEEKDAYS[date.getUTCDay()]; +}; +/** + * @see: + */ +var monthRange = function (year, month) { + var date = datetime(year, month + 1, 1); + return [getWeekday(date), getMonthDays(date)]; +}; +/** + * @see: + */ +var combine = function (date, time) { + time = time || date; + return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), time.getHours(), time.getMinutes(), time.getSeconds(), time.getMilliseconds())); +}; +var dateutil_clone = function (date) { + var dolly = new Date(date.getTime()); + return dolly; +}; +var cloneDates = function (dates) { + var clones = []; + for (var i = 0; i < dates.length; i++) { + clones.push(dateutil_clone(dates[i])); + } + return clones; +}; +/** + * Sorts an array of Date or Time objects + */ +var sort = function (dates) { + dates.sort(function (a, b) { + return a.getTime() - b.getTime(); + }); +}; +var timeToUntilString = function (time, utc) { + if (utc === void 0) { utc = true; } + var date = new Date(time); + return [ + padStart(date.getUTCFullYear().toString(), 4, '0'), + padStart(date.getUTCMonth() + 1, 2, '0'), + padStart(date.getUTCDate(), 2, '0'), + 'T', + padStart(date.getUTCHours(), 2, '0'), + padStart(date.getUTCMinutes(), 2, '0'), + padStart(date.getUTCSeconds(), 2, '0'), + utc ? 'Z' : '', + ].join(''); +}; +var untilStringToDate = function (until) { + var re = /^(\d{4})(\d{2})(\d{2})(T(\d{2})(\d{2})(\d{2})Z?)?$/; + var bits = re.exec(until); + if (!bits) + throw new Error("Invalid UNTIL value: ".concat(until)); + return new Date(Date.UTC(parseInt(bits[1], 10), parseInt(bits[2], 10) - 1, parseInt(bits[3], 10), parseInt(bits[5], 10) || 0, parseInt(bits[6], 10) || 0, parseInt(bits[7], 10) || 0)); +}; +var dateTZtoISO8601 = function (date, timeZone) { + // date format for sv-SE is almost ISO8601 + var dateStr = date.toLocaleString('sv-SE', { timeZone: timeZone }); + // '2023-02-07 10:41:36' + return dateStr.replace(' ', 'T') + 'Z'; +}; +var dateInTimeZone = function (date, timeZone) { + var localTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone; + // Date constructor can only reliably parse dates in ISO8601 format + var dateInLocalTZ = new Date(dateTZtoISO8601(date, localTimeZone)); + var dateInTargetTZ = new Date(dateTZtoISO8601(date, timeZone !== null && timeZone !== void 0 ? timeZone : 'UTC')); + var tzOffset = dateInTargetTZ.getTime() - dateInLocalTZ.getTime(); + return new Date(date.getTime() - tzOffset); +}; + +;// CONCATENATED MODULE: ./src/iterresult.ts +/** + * This class helps us to emulate python's generators, sorta. + */ +var IterResult = /** @class */ (function () { + function IterResult(method, args) { + this.minDate = null; + this.maxDate = null; + this._result = []; + this.total = 0; + this.method = method; + this.args = args; + if (method === 'between') { + this.maxDate = args.inc + ? args.before + : new Date(args.before.getTime() - 1); + this.minDate = args.inc ? args.after : new Date(args.after.getTime() + 1); + } + else if (method === 'before') { + this.maxDate = args.inc ? args.dt : new Date(args.dt.getTime() - 1); + } + else if (method === 'after') { + this.minDate = args.inc ? args.dt : new Date(args.dt.getTime() + 1); + } + } + /** + * Possibly adds a date into the result. + * + * @param {Date} date - the date isn't necessarly added to the result + * list (if it is too late/too early) + * @return {Boolean} true if it makes sense to continue the iteration + * false if we're done. + */ + IterResult.prototype.accept = function (date) { + ++this.total; + var tooEarly = this.minDate && date < this.minDate; + var tooLate = this.maxDate && date > this.maxDate; + if (this.method === 'between') { + if (tooEarly) + return true; + if (tooLate) + return false; + } + else if (this.method === 'before') { + if (tooLate) + return false; + } + else if (this.method === 'after') { + if (tooEarly) + return true; + this.add(date); + return false; + } + return this.add(date); + }; + /** + * + * @param {Date} date that is part of the result. + * @return {Boolean} whether we are interested in more values. + */ + IterResult.prototype.add = function (date) { + this._result.push(date); + return true; + }; + /** + * 'before' and 'after' return only one date, whereas 'all' + * and 'between' an array. + * + * @return {Date,Array?} + */ + IterResult.prototype.getValue = function () { + var res = this._result; + switch (this.method) { + case 'all': + case 'between': + return res; + case 'before': + case 'after': + default: + return (res.length ? res[res.length - 1] : null); + } + }; + IterResult.prototype.clone = function () { + return new IterResult(this.method, this.args); + }; + return IterResult; +}()); +/* harmony default export */ const iterresult = (IterResult); + +;// CONCATENATED MODULE: ./node_modules/tslib/tslib.es6.js +/****************************************************************************** +Copyright (c) Microsoft Corporation. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. +***************************************************************************** */ +/* global Reflect, Promise */ + +var extendStatics = function(d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); +}; + +function __extends(d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); +} + +var __assign = function() { + __assign = Object.assign || function __assign(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; + } + return t; + } + return __assign.apply(this, arguments); +} + +function __rest(s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) + t[p] = s[p]; + if (s != null && typeof Object.getOwnPropertySymbols === "function") + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { + if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) + t[p[i]] = s[p[i]]; + } + return t; +} + +function __decorate(decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +} + +function __param(paramIndex, decorator) { + return function (target, key) { decorator(target, key, paramIndex); } +} + +function __metadata(metadataKey, metadataValue) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue); +} + +function __awaiter(thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +} + +function __generator(thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +} + +var __createBinding = Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +}); + +function __exportStar(m, o) { + for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p); +} + +function __values(o) { + var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; + if (m) return m.call(o); + if (o && typeof o.length === "number") return { + next: function () { + if (o && i >= o.length) o = void 0; + return { value: o && o[i++], done: !o }; + } + }; + throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); +} + +function __read(o, n) { + var m = typeof Symbol === "function" && o[Symbol.iterator]; + if (!m) return o; + var i = m.call(o), r, ar = [], e; + try { + while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); + } + catch (error) { e = { error: error }; } + finally { + try { + if (r && !r.done && (m = i["return"])) m.call(i); + } + finally { if (e) throw e.error; } + } + return ar; +} + +/** @deprecated */ +function __spread() { + for (var ar = [], i = 0; i < arguments.length; i++) + ar = ar.concat(__read(arguments[i])); + return ar; +} + +/** @deprecated */ +function __spreadArrays() { + for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length; + for (var r = Array(s), k = 0, i = 0; i < il; i++) + for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) + r[k] = a[j]; + return r; +} + +function __spreadArray(to, from, pack) { + if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { + if (ar || !(i in from)) { + if (!ar) ar = Array.prototype.slice.call(from, 0, i); + ar[i] = from[i]; + } + } + return to.concat(ar || Array.prototype.slice.call(from)); +} + +function __await(v) { + return this instanceof __await ? (this.v = v, this) : new __await(v); +} + +function __asyncGenerator(thisArg, _arguments, generator) { + if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); + var g = generator.apply(thisArg, _arguments || []), i, q = []; + return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i; + function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; } + function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } } + function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); } + function fulfill(value) { resume("next", value); } + function reject(value) { resume("throw", value); } + function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); } +} + +function __asyncDelegator(o) { + var i, p; + return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i; + function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : f ? f(v) : v; } : f; } +} + +function __asyncValues(o) { + if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined."); + var m = o[Symbol.asyncIterator], i; + return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i); + function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; } + function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); } +} + +function __makeTemplateObject(cooked, raw) { + if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; } + return cooked; +}; + +var __setModuleDefault = Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}; + +function __importStar(mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +} + +function __importDefault(mod) { + return (mod && mod.__esModule) ? mod : { default: mod }; +} + +function __classPrivateFieldGet(receiver, state, kind, f) { + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); + return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); +} + +function __classPrivateFieldSet(receiver, state, value, kind, f) { + if (kind === "m") throw new TypeError("Private method is not writable"); + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); + return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; +} + +function __classPrivateFieldIn(state, receiver) { + if (receiver === null || (typeof receiver !== "object" && typeof receiver !== "function")) throw new TypeError("Cannot use 'in' operator on non-object"); + return typeof state === "function" ? receiver === state : state.has(receiver); +} + +;// CONCATENATED MODULE: ./src/callbackiterresult.ts + + +/** + * IterResult subclass that calls a callback function on each add, + * and stops iterating when the callback returns false. + */ +var CallbackIterResult = /** @class */ (function (_super) { + __extends(CallbackIterResult, _super); + function CallbackIterResult(method, args, iterator) { + var _this = _super.call(this, method, args) || this; + _this.iterator = iterator; + return _this; + } + CallbackIterResult.prototype.add = function (date) { + if (this.iterator(date, this._result.length)) { + this._result.push(date); + return true; + } + return false; + }; + return CallbackIterResult; +}(iterresult)); +/* harmony default export */ const callbackiterresult = (CallbackIterResult); + +;// CONCATENATED MODULE: ./src/nlp/i18n.ts +// ============================================================================= +// i18n +// ============================================================================= +var ENGLISH = { + dayNames: [ + 'Sunday', + 'Monday', + 'Tuesday', + 'Wednesday', + 'Thursday', + 'Friday', + 'Saturday', + ], + monthNames: [ + 'January', + 'February', + 'March', + 'April', + 'May', + 'June', + 'July', + 'August', + 'September', + 'October', + 'November', + 'December', + ], + tokens: { + SKIP: /^[ \r\n\t]+|^\.$/, + number: /^[1-9][0-9]*/, + numberAsText: /^(one|two|three)/i, + every: /^every/i, + 'day(s)': /^days?/i, + 'weekday(s)': /^weekdays?/i, + 'week(s)': /^weeks?/i, + 'hour(s)': /^hours?/i, + 'minute(s)': /^minutes?/i, + 'month(s)': /^months?/i, + 'year(s)': /^years?/i, + on: /^(on|in)/i, + at: /^(at)/i, + the: /^the/i, + first: /^first/i, + second: /^second/i, + third: /^third/i, + nth: /^([1-9][0-9]*)(\.|th|nd|rd|st)/i, + last: /^last/i, + for: /^for/i, + 'time(s)': /^times?/i, + until: /^(un)?til/i, + monday: /^mo(n(day)?)?/i, + tuesday: /^tu(e(s(day)?)?)?/i, + wednesday: /^we(d(n(esday)?)?)?/i, + thursday: /^th(u(r(sday)?)?)?/i, + friday: /^fr(i(day)?)?/i, + saturday: /^sa(t(urday)?)?/i, + sunday: /^su(n(day)?)?/i, + january: /^jan(uary)?/i, + february: /^feb(ruary)?/i, + march: /^mar(ch)?/i, + april: /^apr(il)?/i, + may: /^may/i, + june: /^june?/i, + july: /^july?/i, + august: /^aug(ust)?/i, + september: /^sep(t(ember)?)?/i, + october: /^oct(ober)?/i, + november: /^nov(ember)?/i, + december: /^dec(ember)?/i, + comma: /^(,\s*|(and|or)\s*)+/i, + }, +}; +/* harmony default export */ const i18n = (ENGLISH); + +;// CONCATENATED MODULE: ./src/nlp/totext.ts + + + +// ============================================================================= +// Helper functions +// ============================================================================= +/** + * Return true if a value is in an array + */ +var contains = function (arr, val) { + return arr.indexOf(val) !== -1; +}; +var defaultGetText = function (id) { return id.toString(); }; +var defaultDateFormatter = function (year, month, day) { return "".concat(month, " ").concat(day, ", ").concat(year); }; +/** + * + * @param {RRule} rrule + * Optional: + * @param {Function} gettext function + * @param {Object} language definition + * @constructor + */ +var ToText = /** @class */ (function () { + function ToText(rrule, gettext, language, dateFormatter) { + if (gettext === void 0) { gettext = defaultGetText; } + if (language === void 0) { language = i18n; } + if (dateFormatter === void 0) { dateFormatter = defaultDateFormatter; } + this.text = []; + this.language = language || i18n; + this.gettext = gettext; + this.dateFormatter = dateFormatter; + this.rrule = rrule; + this.options = rrule.options; + this.origOptions = rrule.origOptions; + if (this.origOptions.bymonthday) { + var bymonthday = [].concat(this.options.bymonthday); + var bynmonthday = [].concat(this.options.bynmonthday); + bymonthday.sort(function (a, b) { return a - b; }); + bynmonthday.sort(function (a, b) { return b - a; }); + // 1, 2, 3, .., -5, -4, -3, .. + this.bymonthday = bymonthday.concat(bynmonthday); + if (!this.bymonthday.length) + this.bymonthday = null; + } + if (isPresent(this.origOptions.byweekday)) { + var byweekday = !isArray(this.origOptions.byweekday) + ? [this.origOptions.byweekday] + : this.origOptions.byweekday; + var days = String(byweekday); + this.byweekday = { + allWeeks: byweekday.filter(function (weekday) { + return !weekday.n; + }), + someWeeks: byweekday.filter(function (weekday) { + return Boolean(weekday.n); + }), + isWeekdays: days.indexOf('MO') !== -1 && + days.indexOf('TU') !== -1 && + days.indexOf('WE') !== -1 && + days.indexOf('TH') !== -1 && + days.indexOf('FR') !== -1 && + days.indexOf('SA') === -1 && + days.indexOf('SU') === -1, + isEveryDay: days.indexOf('MO') !== -1 && + days.indexOf('TU') !== -1 && + days.indexOf('WE') !== -1 && + days.indexOf('TH') !== -1 && + days.indexOf('FR') !== -1 && + days.indexOf('SA') !== -1 && + days.indexOf('SU') !== -1, + }; + var sortWeekDays = function (a, b) { + return a.weekday - b.weekday; + }; + this.byweekday.allWeeks.sort(sortWeekDays); + this.byweekday.someWeeks.sort(sortWeekDays); + if (!this.byweekday.allWeeks.length) + this.byweekday.allWeeks = null; + if (!this.byweekday.someWeeks.length) + this.byweekday.someWeeks = null; + } + else { + this.byweekday = null; + } + } + /** + * Test whether the rrule can be fully converted to text. + * + * @param {RRule} rrule + * @return {Boolean} + */ + ToText.isFullyConvertible = function (rrule) { + var canConvert = true; + if (!(rrule.options.freq in ToText.IMPLEMENTED)) + return false; + if (rrule.origOptions.until && rrule.origOptions.count) + return false; + for (var key in rrule.origOptions) { + if (contains(['dtstart', 'tzid', 'wkst', 'freq'], key)) + return true; + if (!contains(ToText.IMPLEMENTED[rrule.options.freq], key)) + return false; + } + return canConvert; + }; + ToText.prototype.isFullyConvertible = function () { + return ToText.isFullyConvertible(this.rrule); + }; + /** + * Perform the conversion. Only some of the frequencies are supported. + * If some of the rrule's options aren't supported, they'll + * be omitted from the output an "(~ approximate)" will be appended. + * + * @return {*} + */ + ToText.prototype.toString = function () { + var gettext = this.gettext; + if (!(this.options.freq in ToText.IMPLEMENTED)) { + return gettext('RRule error: Unable to fully convert this rrule to text'); + } + this.text = [gettext('every')]; + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + this[RRule.FREQUENCIES[this.options.freq]](); + if (this.options.until) { + this.add(gettext('until')); + var until = this.options.until; + this.add(this.dateFormatter(until.getUTCFullYear(), this.language.monthNames[until.getUTCMonth()], until.getUTCDate())); + } + else if (this.options.count) { + this.add(gettext('for')) + .add(this.options.count.toString()) + .add(this.plural(this.options.count) ? gettext('times') : gettext('time')); + } + if (!this.isFullyConvertible()) + this.add(gettext('(~ approximate)')); + return this.text.join(''); + }; + ToText.prototype.HOURLY = function () { + var gettext = this.gettext; + if (this.options.interval !== 1) + this.add(this.options.interval.toString()); + this.add(this.plural(this.options.interval) ? gettext('hours') : gettext('hour')); + }; + ToText.prototype.MINUTELY = function () { + var gettext = this.gettext; + if (this.options.interval !== 1) + this.add(this.options.interval.toString()); + this.add(this.plural(this.options.interval) + ? gettext('minutes') + : gettext('minute')); + }; + ToText.prototype.DAILY = function () { + var gettext = this.gettext; + if (this.options.interval !== 1) + this.add(this.options.interval.toString()); + if (this.byweekday && this.byweekday.isWeekdays) { + this.add(this.plural(this.options.interval) + ? gettext('weekdays') + : gettext('weekday')); + } + else { + this.add(this.plural(this.options.interval) ? gettext('days') : gettext('day')); + } + if (this.origOptions.bymonth) { + this.add(gettext('in')); + this._bymonth(); + } + if (this.bymonthday) { + this._bymonthday(); + } + else if (this.byweekday) { + this._byweekday(); + } + else if (this.origOptions.byhour) { + this._byhour(); + } + }; + ToText.prototype.WEEKLY = function () { + var gettext = this.gettext; + if (this.options.interval !== 1) { + this.add(this.options.interval.toString()).add(this.plural(this.options.interval) ? gettext('weeks') : gettext('week')); + } + if (this.byweekday && this.byweekday.isWeekdays) { + if (this.options.interval === 1) { + this.add(this.plural(this.options.interval) + ? gettext('weekdays') + : gettext('weekday')); + } + else { + this.add(gettext('on')).add(gettext('weekdays')); + } + } + else if (this.byweekday && this.byweekday.isEveryDay) { + this.add(this.plural(this.options.interval) ? gettext('days') : gettext('day')); + } + else { + if (this.options.interval === 1) + this.add(gettext('week')); + if (this.origOptions.bymonth) { + this.add(gettext('in')); + this._bymonth(); + } + if (this.bymonthday) { + this._bymonthday(); + } + else if (this.byweekday) { + this._byweekday(); + } + if (this.origOptions.byhour) { + this._byhour(); + } + } + }; + ToText.prototype.MONTHLY = function () { + var gettext = this.gettext; + if (this.origOptions.bymonth) { + if (this.options.interval !== 1) { + this.add(this.options.interval.toString()).add(gettext('months')); + if (this.plural(this.options.interval)) + this.add(gettext('in')); + } + else { + // this.add(gettext('MONTH')) + } + this._bymonth(); + } + else { + if (this.options.interval !== 1) { + this.add(this.options.interval.toString()); + } + this.add(this.plural(this.options.interval) + ? gettext('months') + : gettext('month')); + } + if (this.bymonthday) { + this._bymonthday(); + } + else if (this.byweekday && this.byweekday.isWeekdays) { + this.add(gettext('on')).add(gettext('weekdays')); + } + else if (this.byweekday) { + this._byweekday(); + } + }; + ToText.prototype.YEARLY = function () { + var gettext = this.gettext; + if (this.origOptions.bymonth) { + if (this.options.interval !== 1) { + this.add(this.options.interval.toString()); + this.add(gettext('years')); + } + else { + // this.add(gettext('YEAR')) + } + this._bymonth(); + } + else { + if (this.options.interval !== 1) { + this.add(this.options.interval.toString()); + } + this.add(this.plural(this.options.interval) ? gettext('years') : gettext('year')); + } + if (this.bymonthday) { + this._bymonthday(); + } + else if (this.byweekday) { + this._byweekday(); + } + if (this.options.byyearday) { + this.add(gettext('on the')) + .add(this.list(this.options.byyearday, this.nth, gettext('and'))) + .add(gettext('day')); + } + if (this.options.byweekno) { + this.add(gettext('in')) + .add(this.plural(this.options.byweekno.length) + ? gettext('weeks') + : gettext('week')) + .add(this.list(this.options.byweekno, undefined, gettext('and'))); + } + }; + ToText.prototype._bymonthday = function () { + var gettext = this.gettext; + if (this.byweekday && this.byweekday.allWeeks) { + this.add(gettext('on')) + .add(this.list(this.byweekday.allWeeks, this.weekdaytext, gettext('or'))) + .add(gettext('the')) + .add(this.list(this.bymonthday, this.nth, gettext('or'))); + } + else { + this.add(gettext('on the')).add(this.list(this.bymonthday, this.nth, gettext('and'))); + } + // this.add(gettext('DAY')) + }; + ToText.prototype._byweekday = function () { + var gettext = this.gettext; + if (this.byweekday.allWeeks && !this.byweekday.isWeekdays) { + this.add(gettext('on')).add(this.list(this.byweekday.allWeeks, this.weekdaytext)); + } + if (this.byweekday.someWeeks) { + if (this.byweekday.allWeeks) + this.add(gettext('and')); + this.add(gettext('on the')).add(this.list(this.byweekday.someWeeks, this.weekdaytext, gettext('and'))); + } + }; + ToText.prototype._byhour = function () { + var gettext = this.gettext; + this.add(gettext('at')).add(this.list(this.origOptions.byhour, undefined, gettext('and'))); + }; + ToText.prototype._bymonth = function () { + this.add(this.list(this.options.bymonth, this.monthtext, this.gettext('and'))); + }; + ToText.prototype.nth = function (n) { + n = parseInt(n.toString(), 10); + var nth; + var gettext = this.gettext; + if (n === -1) + return gettext('last'); + var npos = Math.abs(n); + switch (npos) { + case 1: + case 21: + case 31: + nth = npos + gettext('st'); + break; + case 2: + case 22: + nth = npos + gettext('nd'); + break; + case 3: + case 23: + nth = npos + gettext('rd'); + break; + default: + nth = npos + gettext('th'); + } + return n < 0 ? nth + ' ' + gettext('last') : nth; + }; + ToText.prototype.monthtext = function (m) { + return this.language.monthNames[m - 1]; + }; + ToText.prototype.weekdaytext = function (wday) { + var weekday = isNumber(wday) ? (wday + 1) % 7 : wday.getJsWeekday(); + return ((wday.n ? this.nth(wday.n) + ' ' : '') + + this.language.dayNames[weekday]); + }; + ToText.prototype.plural = function (n) { + return n % 100 !== 1; + }; + ToText.prototype.add = function (s) { + this.text.push(' '); + this.text.push(s); + return this; + }; + ToText.prototype.list = function (arr, callback, finalDelim, delim) { + var _this = this; + if (delim === void 0) { delim = ','; } + if (!isArray(arr)) { + arr = [arr]; + } + var delimJoin = function (array, delimiter, finalDelimiter) { + var list = ''; + for (var i = 0; i < array.length; i++) { + if (i !== 0) { + if (i === array.length - 1) { + list += ' ' + finalDelimiter + ' '; + } + else { + list += delimiter + ' '; + } + } + list += array[i]; + } + return list; + }; + callback = + callback || + function (o) { + return o.toString(); + }; + var realCallback = function (arg) { + return callback && callback.call(_this, arg); + }; + if (finalDelim) { + return delimJoin(arr.map(realCallback), delim, finalDelim); + } + else { + return arr.map(realCallback).join(delim + ' '); + } + }; + return ToText; +}()); +/* harmony default export */ const totext = (ToText); + +;// CONCATENATED MODULE: ./src/nlp/parsetext.ts + + +// ============================================================================= +// Parser +// ============================================================================= +var Parser = /** @class */ (function () { + function Parser(rules) { + this.done = true; + this.rules = rules; + } + Parser.prototype.start = function (text) { + this.text = text; + this.done = false; + return this.nextSymbol(); + }; + Parser.prototype.isDone = function () { + return this.done && this.symbol === null; + }; + Parser.prototype.nextSymbol = function () { + var best; + var bestSymbol; + this.symbol = null; + this.value = null; + do { + if (this.done) + return false; + var rule = void 0; + best = null; + for (var name_1 in this.rules) { + rule = this.rules[name_1]; + var match = rule.exec(this.text); + if (match) { + if (best === null || match[0].length > best[0].length) { + best = match; + bestSymbol = name_1; + } + } + } + if (best != null) { + this.text = this.text.substr(best[0].length); + if (this.text === '') + this.done = true; + } + if (best == null) { + this.done = true; + this.symbol = null; + this.value = null; + return; + } + } while (bestSymbol === 'SKIP'); + this.symbol = bestSymbol; + this.value = best; + return true; + }; + Parser.prototype.accept = function (name) { + if (this.symbol === name) { + if (this.value) { + var v = this.value; + this.nextSymbol(); + return v; + } + this.nextSymbol(); + return true; + } + return false; + }; + Parser.prototype.acceptNumber = function () { + return this.accept('number'); + }; + Parser.prototype.expect = function (name) { + if (this.accept(name)) + return true; + throw new Error('expected ' + name + ' but found ' + this.symbol); + }; + return Parser; +}()); +function parseText(text, language) { + if (language === void 0) { language = i18n; } + var options = {}; + var ttr = new Parser(language.tokens); + if (!ttr.start(text)) + return null; + S(); + return options; + function S() { + // every [n] + ttr.expect('every'); + var n = ttr.acceptNumber(); + if (n) + options.interval = parseInt(n[0], 10); + if (ttr.isDone()) + throw new Error('Unexpected end'); + switch (ttr.symbol) { + case 'day(s)': + options.freq = RRule.DAILY; + if (ttr.nextSymbol()) { + AT(); + F(); + } + break; + // FIXME Note: every 2 weekdays != every two weeks on weekdays. + // DAILY on weekdays is not a valid rule + case 'weekday(s)': + options.freq = RRule.WEEKLY; + options.byweekday = [RRule.MO, RRule.TU, RRule.WE, RRule.TH, RRule.FR]; + ttr.nextSymbol(); + AT(); + F(); + break; + case 'week(s)': + options.freq = RRule.WEEKLY; + if (ttr.nextSymbol()) { + ON(); + AT(); + F(); + } + break; + case 'hour(s)': + options.freq = RRule.HOURLY; + if (ttr.nextSymbol()) { + ON(); + F(); + } + break; + case 'minute(s)': + options.freq = RRule.MINUTELY; + if (ttr.nextSymbol()) { + ON(); + F(); + } + break; + case 'month(s)': + options.freq = RRule.MONTHLY; + if (ttr.nextSymbol()) { + ON(); + F(); + } + break; + case 'year(s)': + options.freq = RRule.YEARLY; + if (ttr.nextSymbol()) { + ON(); + F(); + } + break; + case 'monday': + case 'tuesday': + case 'wednesday': + case 'thursday': + case 'friday': + case 'saturday': + case 'sunday': + options.freq = RRule.WEEKLY; + var key = ttr.symbol + .substr(0, 2) + .toUpperCase(); + options.byweekday = [RRule[key]]; + if (!ttr.nextSymbol()) + return; + // TODO check for duplicates + while (ttr.accept('comma')) { + if (ttr.isDone()) + throw new Error('Unexpected end'); + var wkd = decodeWKD(); + if (!wkd) { + throw new Error('Unexpected symbol ' + ttr.symbol + ', expected weekday'); + } + options.byweekday.push(RRule[wkd]); + ttr.nextSymbol(); + } + AT(); + MDAYs(); + F(); + break; + case 'january': + case 'february': + case 'march': + case 'april': + case 'may': + case 'june': + case 'july': + case 'august': + case 'september': + case 'october': + case 'november': + case 'december': + options.freq = RRule.YEARLY; + options.bymonth = [decodeM()]; + if (!ttr.nextSymbol()) + return; + // TODO check for duplicates + while (ttr.accept('comma')) { + if (ttr.isDone()) + throw new Error('Unexpected end'); + var m = decodeM(); + if (!m) { + throw new Error('Unexpected symbol ' + ttr.symbol + ', expected month'); + } + options.bymonth.push(m); + ttr.nextSymbol(); + } + ON(); + F(); + break; + default: + throw new Error('Unknown symbol'); + } + } + function ON() { + var on = ttr.accept('on'); + var the = ttr.accept('the'); + if (!(on || the)) + return; + do { + var nth = decodeNTH(); + var wkd = decodeWKD(); + var m = decodeM(); + // nth | + if (nth) { + // ttr.nextSymbol() + if (wkd) { + ttr.nextSymbol(); + if (!options.byweekday) + options.byweekday = []; + options.byweekday.push(RRule[wkd].nth(nth)); + } + else { + if (!options.bymonthday) + options.bymonthday = []; + options.bymonthday.push(nth); + ttr.accept('day(s)'); + } + // + } + else if (wkd) { + ttr.nextSymbol(); + if (!options.byweekday) + options.byweekday = []; + options.byweekday.push(RRule[wkd]); + } + else if (ttr.symbol === 'weekday(s)') { + ttr.nextSymbol(); + if (!options.byweekday) { + options.byweekday = [RRule.MO, RRule.TU, RRule.WE, RRule.TH, RRule.FR]; + } + } + else if (ttr.symbol === 'week(s)') { + ttr.nextSymbol(); + var n = ttr.acceptNumber(); + if (!n) { + throw new Error('Unexpected symbol ' + ttr.symbol + ', expected week number'); + } + options.byweekno = [parseInt(n[0], 10)]; + while (ttr.accept('comma')) { + n = ttr.acceptNumber(); + if (!n) { + throw new Error('Unexpected symbol ' + ttr.symbol + '; expected monthday'); + } + options.byweekno.push(parseInt(n[0], 10)); + } + } + else if (m) { + ttr.nextSymbol(); + if (!options.bymonth) + options.bymonth = []; + options.bymonth.push(m); + } + else { + return; + } + } while (ttr.accept('comma') || ttr.accept('the') || ttr.accept('on')); + } + function AT() { + var at = ttr.accept('at'); + if (!at) + return; + do { + var n = ttr.acceptNumber(); + if (!n) { + throw new Error('Unexpected symbol ' + ttr.symbol + ', expected hour'); + } + options.byhour = [parseInt(n[0], 10)]; + while (ttr.accept('comma')) { + n = ttr.acceptNumber(); + if (!n) { + throw new Error('Unexpected symbol ' + ttr.symbol + '; expected hour'); + } + options.byhour.push(parseInt(n[0], 10)); + } + } while (ttr.accept('comma') || ttr.accept('at')); + } + function decodeM() { + switch (ttr.symbol) { + case 'january': + return 1; + case 'february': + return 2; + case 'march': + return 3; + case 'april': + return 4; + case 'may': + return 5; + case 'june': + return 6; + case 'july': + return 7; + case 'august': + return 8; + case 'september': + return 9; + case 'october': + return 10; + case 'november': + return 11; + case 'december': + return 12; + default: + return false; + } + } + function decodeWKD() { + switch (ttr.symbol) { + case 'monday': + case 'tuesday': + case 'wednesday': + case 'thursday': + case 'friday': + case 'saturday': + case 'sunday': + return ttr.symbol.substr(0, 2).toUpperCase(); + default: + return false; + } + } + function decodeNTH() { + switch (ttr.symbol) { + case 'last': + ttr.nextSymbol(); + return -1; + case 'first': + ttr.nextSymbol(); + return 1; + case 'second': + ttr.nextSymbol(); + return ttr.accept('last') ? -2 : 2; + case 'third': + ttr.nextSymbol(); + return ttr.accept('last') ? -3 : 3; + case 'nth': + var v = parseInt(ttr.value[1], 10); + if (v < -366 || v > 366) + throw new Error('Nth out of range: ' + v); + ttr.nextSymbol(); + return ttr.accept('last') ? -v : v; + default: + return false; + } + } + function MDAYs() { + ttr.accept('on'); + ttr.accept('the'); + var nth = decodeNTH(); + if (!nth) + return; + options.bymonthday = [nth]; + ttr.nextSymbol(); + while (ttr.accept('comma')) { + nth = decodeNTH(); + if (!nth) { + throw new Error('Unexpected symbol ' + ttr.symbol + '; expected monthday'); + } + options.bymonthday.push(nth); + ttr.nextSymbol(); + } + } + function F() { + if (ttr.symbol === 'until') { + var date = Date.parse(ttr.text); + if (!date) + throw new Error('Cannot parse until date:' + ttr.text); + options.until = new Date(date); + } + else if (ttr.accept('for')) { + options.count = parseInt(ttr.value[0], 10); + ttr.expect('number'); + // ttr.expect('times') + } + } +} + +;// CONCATENATED MODULE: ./src/types.ts +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 || (Frequency = {})); +function freqIsDailyOrGreater(freq) { + return freq < Frequency.HOURLY; +} + +;// CONCATENATED MODULE: ./src/nlp/index.ts + + + + + +/* ! + * rrule.js - Library for working with recurrence rules for calendar dates. + * https://github.com/jakubroztocil/rrule + * + * Copyright 2010, Jakub Roztocil and Lars Schoning + * Licenced under the BSD licence. + * https://github.com/jakubroztocil/rrule/blob/master/LICENCE + * + */ +/** + * + * Implementation of RRule.fromText() and RRule::toText(). + * + * + * On the client side, this file needs to be included + * when those functions are used. + * + */ +// ============================================================================= +// fromText +// ============================================================================= +/** + * Will be able to convert some of the below described rules from + * text format to a rule object. + * + * + * RULES + * + * Every ([n]) + * day(s) + * | [weekday], ..., (and) [weekday] + * | weekday(s) + * | week(s) + * | month(s) + * | [month], ..., (and) [month] + * | year(s) + * + * + * Plus 0, 1, or multiple of these: + * + * on [weekday], ..., (or) [weekday] the [monthday], [monthday], ... (or) [monthday] + * + * on [weekday], ..., (and) [weekday] + * + * on the [monthday], [monthday], ... (and) [monthday] (day of the month) + * + * on the [nth-weekday], ..., (and) [nth-weekday] (of the month/year) + * + * + * Plus 0 or 1 of these: + * + * for [n] time(s) + * + * until [date] + * + * Plus (.) + * + * + * Definitely no supported for parsing: + * + * (for year): + * in week(s) [n], ..., (and) [n] + * + * on the [yearday], ..., (and) [n] day of the year + * on day [yearday], ..., (and) [n] + * + * + * NON-TERMINALS + * + * [n]: 1, 2 ..., one, two, three .. + * [month]: January, February, March, April, May, ... December + * [weekday]: Monday, ... Sunday + * [nth-weekday]: first [weekday], 2nd [weekday], ... last [weekday], ... + * [monthday]: first, 1., 2., 1st, 2nd, second, ... 31st, last day, 2nd last day, .. + * [date]: + * - [month] (0-31(,) ([year])), + * - (the) 0-31.(1-12.([year])), + * - (the) 0-31/(1-12/([year])), + * - [weekday] + * + * [year]: 0000, 0001, ... 01, 02, .. + * + * Definitely not supported for parsing: + * + * [yearday]: first, 1., 2., 1st, 2nd, second, ... 366th, last day, 2nd last day, .. + * + * @param {String} text + * @return {Object, Boolean} the rule, or null. + */ +var fromText = function (text, language) { + if (language === void 0) { language = i18n; } + return new RRule(parseText(text, language) || undefined); +}; +var common = [ + 'count', + 'until', + 'interval', + 'byweekday', + 'bymonthday', + 'bymonth', +]; +totext.IMPLEMENTED = []; +totext.IMPLEMENTED[Frequency.HOURLY] = common; +totext.IMPLEMENTED[Frequency.MINUTELY] = common; +totext.IMPLEMENTED[Frequency.DAILY] = ['byhour'].concat(common); +totext.IMPLEMENTED[Frequency.WEEKLY] = common; +totext.IMPLEMENTED[Frequency.MONTHLY] = common; +totext.IMPLEMENTED[Frequency.YEARLY] = ['byweekno', 'byyearday'].concat(common); +// ============================================================================= +// Export +// ============================================================================= +var toText = function (rrule, gettext, language, dateFormatter) { + return new totext(rrule, gettext, language, dateFormatter).toString(); +}; +var isFullyConvertible = totext.isFullyConvertible; + + +;// CONCATENATED MODULE: ./src/datetime.ts + + + + +var Time = /** @class */ (function () { + function Time(hour, minute, second, millisecond) { + this.hour = hour; + this.minute = minute; + this.second = second; + this.millisecond = millisecond || 0; + } + Time.prototype.getHours = function () { + return this.hour; + }; + Time.prototype.getMinutes = function () { + return this.minute; + }; + Time.prototype.getSeconds = function () { + return this.second; + }; + Time.prototype.getMilliseconds = function () { + return this.millisecond; + }; + Time.prototype.getTime = function () { + return ((this.hour * 60 * 60 + this.minute * 60 + this.second) * 1000 + + this.millisecond); + }; + return Time; +}()); + +var DateTime = /** @class */ (function (_super) { + __extends(DateTime, _super); + function DateTime(year, month, day, hour, minute, second, millisecond) { + var _this = _super.call(this, hour, minute, second, millisecond) || this; + _this.year = year; + _this.month = month; + _this.day = day; + return _this; + } + DateTime.fromDate = function (date) { + return new this(date.getUTCFullYear(), date.getUTCMonth() + 1, date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds(), date.valueOf() % 1000); + }; + DateTime.prototype.getWeekday = function () { + return getWeekday(new Date(this.getTime())); + }; + DateTime.prototype.getTime = function () { + return new Date(Date.UTC(this.year, this.month - 1, this.day, this.hour, this.minute, this.second, this.millisecond)).getTime(); + }; + DateTime.prototype.getDay = function () { + return this.day; + }; + DateTime.prototype.getMonth = function () { + return this.month; + }; + DateTime.prototype.getYear = function () { + return this.year; + }; + DateTime.prototype.addYears = function (years) { + this.year += years; + }; + DateTime.prototype.addMonths = function (months) { + this.month += months; + if (this.month > 12) { + var yearDiv = Math.floor(this.month / 12); + var monthMod = pymod(this.month, 12); + this.month = monthMod; + this.year += yearDiv; + if (this.month === 0) { + this.month = 12; + --this.year; + } + } + }; + DateTime.prototype.addWeekly = function (days, wkst) { + if (wkst > this.getWeekday()) { + this.day += -(this.getWeekday() + 1 + (6 - wkst)) + days * 7; + } + else { + this.day += -(this.getWeekday() - wkst) + days * 7; + } + this.fixDay(); + }; + DateTime.prototype.addDaily = function (days) { + this.day += days; + this.fixDay(); + }; + DateTime.prototype.addHours = function (hours, filtered, byhour) { + if (filtered) { + // Jump to one iteration before next day + this.hour += Math.floor((23 - this.hour) / hours) * hours; + } + for (;;) { + this.hour += hours; + var _a = divmod(this.hour, 24), dayDiv = _a.div, hourMod = _a.mod; + if (dayDiv) { + this.hour = hourMod; + this.addDaily(dayDiv); + } + if (empty(byhour) || includes(byhour, this.hour)) + break; + } + }; + DateTime.prototype.addMinutes = function (minutes, filtered, byhour, byminute) { + if (filtered) { + // Jump to one iteration before next day + this.minute += + Math.floor((1439 - (this.hour * 60 + this.minute)) / minutes) * minutes; + } + for (;;) { + this.minute += minutes; + var _a = divmod(this.minute, 60), hourDiv = _a.div, minuteMod = _a.mod; + if (hourDiv) { + this.minute = minuteMod; + this.addHours(hourDiv, false, byhour); + } + if ((empty(byhour) || includes(byhour, this.hour)) && + (empty(byminute) || includes(byminute, this.minute))) { + break; + } + } + }; + DateTime.prototype.addSeconds = function (seconds, filtered, byhour, byminute, bysecond) { + if (filtered) { + // Jump to one iteration before next day + this.second += + Math.floor((86399 - (this.hour * 3600 + this.minute * 60 + this.second)) / + seconds) * seconds; + } + for (;;) { + this.second += seconds; + var _a = divmod(this.second, 60), minuteDiv = _a.div, secondMod = _a.mod; + if (minuteDiv) { + this.second = secondMod; + this.addMinutes(minuteDiv, false, byhour, byminute); + } + if ((empty(byhour) || includes(byhour, this.hour)) && + (empty(byminute) || includes(byminute, this.minute)) && + (empty(bysecond) || includes(bysecond, this.second))) { + break; + } + } + }; + DateTime.prototype.fixDay = function () { + if (this.day <= 28) { + return; + } + var daysinmonth = monthRange(this.year, this.month - 1)[1]; + if (this.day <= daysinmonth) { + return; + } + while (this.day > daysinmonth) { + this.day -= daysinmonth; + ++this.month; + if (this.month === 13) { + this.month = 1; + ++this.year; + if (this.year > MAXYEAR) { + return; + } + } + daysinmonth = monthRange(this.year, this.month - 1)[1]; + } + }; + DateTime.prototype.add = function (options, filtered) { + var freq = options.freq, interval = options.interval, wkst = options.wkst, byhour = options.byhour, byminute = options.byminute, bysecond = options.bysecond; + switch (freq) { + case Frequency.YEARLY: + return this.addYears(interval); + case Frequency.MONTHLY: + return this.addMonths(interval); + case Frequency.WEEKLY: + return this.addWeekly(interval, wkst); + case Frequency.DAILY: + return this.addDaily(interval); + case Frequency.HOURLY: + return this.addHours(interval, filtered, byhour); + case Frequency.MINUTELY: + return this.addMinutes(interval, filtered, byhour, byminute); + case Frequency.SECONDLY: + return this.addSeconds(interval, filtered, byhour, byminute, bysecond); + } + }; + return DateTime; +}(Time)); + + +;// CONCATENATED MODULE: ./src/parseoptions.ts + + + + + + + +function initializeOptions(options) { + var invalid = []; + var keys = Object.keys(options); + // Shallow copy for options and origOptions and check for invalid + for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) { + var key = keys_1[_i]; + if (!includes(defaultKeys, key)) + invalid.push(key); + if (isDate(options[key]) && !isValidDate(options[key])) { + invalid.push(key); + } + } + if (invalid.length) { + throw new Error('Invalid options: ' + invalid.join(', ')); + } + return __assign({}, options); +} +function parseOptions(options) { + var opts = __assign(__assign({}, DEFAULT_OPTIONS), initializeOptions(options)); + if (isPresent(opts.byeaster)) + opts.freq = RRule.YEARLY; + if (!(isPresent(opts.freq) && RRule.FREQUENCIES[opts.freq])) { + throw new Error("Invalid frequency: ".concat(opts.freq, " ").concat(options.freq)); + } + if (!opts.dtstart) + opts.dtstart = new Date(new Date().setMilliseconds(0)); + if (!isPresent(opts.wkst)) { + opts.wkst = RRule.MO.weekday; + } + else if (isNumber(opts.wkst)) { + // cool, just keep it like that + } + else { + opts.wkst = opts.wkst.weekday; + } + if (isPresent(opts.bysetpos)) { + if (isNumber(opts.bysetpos)) + opts.bysetpos = [opts.bysetpos]; + for (var i = 0; i < opts.bysetpos.length; i++) { + var v = opts.bysetpos[i]; + if (v === 0 || !(v >= -366 && v <= 366)) { + throw new Error('bysetpos must be between 1 and 366,' + ' or between -366 and -1'); + } + } + } + if (!(Boolean(opts.byweekno) || + notEmpty(opts.byweekno) || + notEmpty(opts.byyearday) || + Boolean(opts.bymonthday) || + notEmpty(opts.bymonthday) || + isPresent(opts.byweekday) || + isPresent(opts.byeaster))) { + switch (opts.freq) { + case RRule.YEARLY: + if (!opts.bymonth) + opts.bymonth = opts.dtstart.getUTCMonth() + 1; + opts.bymonthday = opts.dtstart.getUTCDate(); + break; + case RRule.MONTHLY: + opts.bymonthday = opts.dtstart.getUTCDate(); + break; + case RRule.WEEKLY: + opts.byweekday = [getWeekday(opts.dtstart)]; + break; + } + } + // bymonth + if (isPresent(opts.bymonth) && !isArray(opts.bymonth)) { + opts.bymonth = [opts.bymonth]; + } + // byyearday + if (isPresent(opts.byyearday) && + !isArray(opts.byyearday) && + isNumber(opts.byyearday)) { + opts.byyearday = [opts.byyearday]; + } + // bymonthday + if (!isPresent(opts.bymonthday)) { + opts.bymonthday = []; + opts.bynmonthday = []; + } + else if (isArray(opts.bymonthday)) { + var bymonthday = []; + var bynmonthday = []; + for (var i = 0; i < opts.bymonthday.length; i++) { + var v = opts.bymonthday[i]; + if (v > 0) { + bymonthday.push(v); + } + else if (v < 0) { + bynmonthday.push(v); + } + } + opts.bymonthday = bymonthday; + opts.bynmonthday = bynmonthday; + } + else if (opts.bymonthday < 0) { + opts.bynmonthday = [opts.bymonthday]; + opts.bymonthday = []; + } + else { + opts.bynmonthday = []; + opts.bymonthday = [opts.bymonthday]; + } + // byweekno + if (isPresent(opts.byweekno) && !isArray(opts.byweekno)) { + opts.byweekno = [opts.byweekno]; + } + // byweekday / bynweekday + if (!isPresent(opts.byweekday)) { + opts.bynweekday = null; + } + else if (isNumber(opts.byweekday)) { + opts.byweekday = [opts.byweekday]; + opts.bynweekday = null; + } + else if (isWeekdayStr(opts.byweekday)) { + opts.byweekday = [Weekday.fromStr(opts.byweekday).weekday]; + opts.bynweekday = null; + } + else if (opts.byweekday instanceof Weekday) { + if (!opts.byweekday.n || opts.freq > RRule.MONTHLY) { + opts.byweekday = [opts.byweekday.weekday]; + opts.bynweekday = null; + } + else { + opts.bynweekday = [[opts.byweekday.weekday, opts.byweekday.n]]; + opts.byweekday = null; + } + } + else { + var byweekday = []; + var bynweekday = []; + for (var i = 0; i < opts.byweekday.length; i++) { + var wday = opts.byweekday[i]; + if (isNumber(wday)) { + byweekday.push(wday); + continue; + } + else if (isWeekdayStr(wday)) { + byweekday.push(Weekday.fromStr(wday).weekday); + continue; + } + if (!wday.n || opts.freq > RRule.MONTHLY) { + byweekday.push(wday.weekday); + } + else { + bynweekday.push([wday.weekday, wday.n]); + } + } + opts.byweekday = notEmpty(byweekday) ? byweekday : null; + opts.bynweekday = notEmpty(bynweekday) ? bynweekday : null; + } + // byhour + if (!isPresent(opts.byhour)) { + opts.byhour = opts.freq < RRule.HOURLY ? [opts.dtstart.getUTCHours()] : null; + } + else if (isNumber(opts.byhour)) { + opts.byhour = [opts.byhour]; + } + // byminute + if (!isPresent(opts.byminute)) { + opts.byminute = + opts.freq < RRule.MINUTELY ? [opts.dtstart.getUTCMinutes()] : null; + } + else if (isNumber(opts.byminute)) { + opts.byminute = [opts.byminute]; + } + // bysecond + if (!isPresent(opts.bysecond)) { + opts.bysecond = + opts.freq < RRule.SECONDLY ? [opts.dtstart.getUTCSeconds()] : null; + } + else if (isNumber(opts.bysecond)) { + opts.bysecond = [opts.bysecond]; + } + return { parsedOptions: opts }; +} +function buildTimeset(opts) { + var millisecondModulo = opts.dtstart.getTime() % 1000; + if (!freqIsDailyOrGreater(opts.freq)) { + return []; + } + var timeset = []; + opts.byhour.forEach(function (hour) { + opts.byminute.forEach(function (minute) { + opts.bysecond.forEach(function (second) { + timeset.push(new Time(hour, minute, second, millisecondModulo)); + }); + }); + }); + return timeset; +} + +;// CONCATENATED MODULE: ./src/parsestring.ts + + + + + +function parseString(rfcString) { + var options = rfcString + .split('\n') + .map(parseLine) + .filter(function (x) { return x !== null; }); + return __assign(__assign({}, options[0]), options[1]); +} +function parseDtstart(line) { + var options = {}; + var dtstartWithZone = /DTSTART(?:;TZID=([^:=]+?))?(?::|=)([^;\s]+)/i.exec(line); + if (!dtstartWithZone) { + return options; + } + var tzid = dtstartWithZone[1], dtstart = dtstartWithZone[2]; + if (tzid) { + options.tzid = tzid; + } + options.dtstart = untilStringToDate(dtstart); + return options; +} +function parseLine(rfcString) { + rfcString = rfcString.replace(/^\s+|\s+$/, ''); + if (!rfcString.length) + return null; + var header = /^([A-Z]+?)[:;]/.exec(rfcString.toUpperCase()); + if (!header) { + return parseRrule(rfcString); + } + var key = header[1]; + switch (key.toUpperCase()) { + case 'RRULE': + case 'EXRULE': + return parseRrule(rfcString); + case 'DTSTART': + return parseDtstart(rfcString); + default: + throw new Error("Unsupported RFC prop ".concat(key, " in ").concat(rfcString)); + } +} +function parseRrule(line) { + var strippedLine = line.replace(/^RRULE:/i, ''); + var options = parseDtstart(strippedLine); + var attrs = line.replace(/^(?:RRULE|EXRULE):/i, '').split(';'); + attrs.forEach(function (attr) { + var _a = attr.split('='), key = _a[0], value = _a[1]; + switch (key.toUpperCase()) { + case 'FREQ': + options.freq = Frequency[value.toUpperCase()]; + break; + case 'WKST': + options.wkst = Days[value.toUpperCase()]; + break; + case 'COUNT': + case 'INTERVAL': + case 'BYSETPOS': + case 'BYMONTH': + case 'BYMONTHDAY': + case 'BYYEARDAY': + case 'BYWEEKNO': + case 'BYHOUR': + case 'BYMINUTE': + case 'BYSECOND': + var num = parseNumber(value); + var optionKey = key.toLowerCase(); + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + options[optionKey] = num; + break; + case 'BYWEEKDAY': + case 'BYDAY': + options.byweekday = parseWeekday(value); + break; + case 'DTSTART': + case 'TZID': + // for backwards compatibility + var dtstart = parseDtstart(line); + options.tzid = dtstart.tzid; + options.dtstart = dtstart.dtstart; + break; + case 'UNTIL': + options.until = untilStringToDate(value); + break; + case 'BYEASTER': + options.byeaster = Number(value); + break; + default: + throw new Error("Unknown RRULE property '" + key + "'"); + } + }); + return options; +} +function parseNumber(value) { + if (value.indexOf(',') !== -1) { + var values = value.split(','); + return values.map(parseIndividualNumber); + } + return parseIndividualNumber(value); +} +function parseIndividualNumber(value) { + if (/^[+-]?\d+$/.test(value)) { + return Number(value); + } + return value; +} +function parseWeekday(value) { + var days = value.split(','); + return days.map(function (day) { + if (day.length === 2) { + // MO, TU, ... + return Days[day]; // wday instanceof Weekday + } + // -1MO, +3FR, 1SO, 13TU ... + var parts = day.match(/^([+-]?\d{1,2})([A-Z]{2})$/); + if (!parts || parts.length < 3) { + throw new SyntaxError("Invalid weekday string: ".concat(day)); + } + var n = Number(parts[1]); + var wdaypart = parts[2]; + var wday = Days[wdaypart].weekday; + return new Weekday(wday, n); + }); +} + +;// CONCATENATED MODULE: ./src/datewithzone.ts + +var DateWithZone = /** @class */ (function () { + function DateWithZone(date, tzid) { + if (isNaN(date.getTime())) { + throw new RangeError('Invalid date passed to DateWithZone'); + } + this.date = date; + this.tzid = tzid; + } + Object.defineProperty(DateWithZone.prototype, "isUTC", { + get: function () { + return !this.tzid || this.tzid.toUpperCase() === 'UTC'; + }, + enumerable: false, + configurable: true + }); + DateWithZone.prototype.toString = function () { + var datestr = timeToUntilString(this.date.getTime(), this.isUTC); + if (!this.isUTC) { + return ";TZID=".concat(this.tzid, ":").concat(datestr); + } + return ":".concat(datestr); + }; + DateWithZone.prototype.getTime = function () { + return this.date.getTime(); + }; + DateWithZone.prototype.rezonedDate = function () { + if (this.isUTC) { + return this.date; + } + return dateInTimeZone(this.date, this.tzid); + }; + return DateWithZone; +}()); + + +;// CONCATENATED MODULE: ./src/optionstostring.ts + + + + + +function optionsToString(options) { + var rrule = []; + var dtstart = ''; + var keys = Object.keys(options); + var defaultKeys = Object.keys(DEFAULT_OPTIONS); + for (var i = 0; i < keys.length; i++) { + if (keys[i] === 'tzid') + continue; + if (!includes(defaultKeys, keys[i])) + continue; + var key = keys[i].toUpperCase(); + var value = options[keys[i]]; + var outValue = ''; + if (!isPresent(value) || (isArray(value) && !value.length)) + continue; + switch (key) { + case 'FREQ': + outValue = RRule.FREQUENCIES[options.freq]; + break; + case 'WKST': + if (isNumber(value)) { + outValue = new Weekday(value).toString(); + } + else { + outValue = value.toString(); + } + break; + case 'BYWEEKDAY': + /* + NOTE: BYWEEKDAY is a special case. + RRule() deconstructs the rule.options.byweekday array + into an array of Weekday arguments. + On the other hand, rule.origOptions is an array of Weekdays. + We need to handle both cases here. + It might be worth change RRule to keep the Weekdays. + + Also, BYWEEKDAY (used by RRule) vs. BYDAY (RFC) + + */ + key = 'BYDAY'; + outValue = toArray(value) + .map(function (wday) { + if (wday instanceof Weekday) { + return wday; + } + if (isArray(wday)) { + return new Weekday(wday[0], wday[1]); + } + return new Weekday(wday); + }) + .toString(); + break; + case 'DTSTART': + dtstart = buildDtstart(value, options.tzid); + break; + case 'UNTIL': + outValue = timeToUntilString(value, !options.tzid); + break; + default: + if (isArray(value)) { + var strValues = []; + for (var j = 0; j < value.length; j++) { + strValues[j] = String(value[j]); + } + outValue = strValues.toString(); + } + else { + outValue = String(value); + } + } + if (outValue) { + rrule.push([key, outValue]); + } + } + var rules = rrule + .map(function (_a) { + var key = _a[0], value = _a[1]; + return "".concat(key, "=").concat(value.toString()); + }) + .join(';'); + var ruleString = ''; + if (rules !== '') { + ruleString = "RRULE:".concat(rules); + } + return [dtstart, ruleString].filter(function (x) { return !!x; }).join('\n'); +} +function buildDtstart(dtstart, tzid) { + if (!dtstart) { + return ''; + } + return 'DTSTART' + new DateWithZone(new Date(dtstart), tzid).toString(); +} + +;// CONCATENATED MODULE: ./src/cache.ts + + + +function argsMatch(left, right) { + if (Array.isArray(left)) { + if (!Array.isArray(right)) + return false; + if (left.length !== right.length) + return false; + return left.every(function (date, i) { return date.getTime() === right[i].getTime(); }); + } + if (left instanceof Date) { + return right instanceof Date && left.getTime() === right.getTime(); + } + return left === right; +} +var Cache = /** @class */ (function () { + function Cache() { + this.all = false; + this.before = []; + this.after = []; + this.between = []; + } + /** + * @param {String} what - all/before/after/between + * @param {Array,Date} value - an array of dates, one date, or null + * @param {Object?} args - _iter arguments + */ + Cache.prototype._cacheAdd = function (what, value, args) { + if (value) { + value = value instanceof Date ? dateutil_clone(value) : cloneDates(value); + } + if (what === 'all') { + this.all = value; + } + else { + args._value = value; + this[what].push(args); + } + }; + /** + * @return false - not in the cache + * @return null - cached, but zero occurrences (before/after) + * @return Date - cached (before/after) + * @return [] - cached, but zero occurrences (all/between) + * @return [Date1, DateN] - cached (all/between) + */ + Cache.prototype._cacheGet = function (what, args) { + var cached = false; + var argsKeys = args ? Object.keys(args) : []; + var findCacheDiff = function (item) { + for (var i = 0; i < argsKeys.length; i++) { + var key = argsKeys[i]; + if (!argsMatch(args[key], item[key])) { + return true; + } + } + return false; + }; + var cachedObject = this[what]; + if (what === 'all') { + cached = this.all; + } + else if (isArray(cachedObject)) { + // Let's see whether we've already called the + // 'what' method with the same 'args' + for (var i = 0; i < cachedObject.length; i++) { + var item = cachedObject[i]; + if (argsKeys.length && findCacheDiff(item)) + continue; + cached = item._value; + break; + } + } + if (!cached && this.all) { + // Not in the cache, but we already know all the occurrences, + // so we can find the correct dates from the cached ones. + var iterResult = new iterresult(what, args); + for (var i = 0; i < this.all.length; i++) { + if (!iterResult.accept(this.all[i])) + break; + } + cached = iterResult.getValue(); + this._cacheAdd(what, cached, args); + } + return isArray(cached) + ? cloneDates(cached) + : cached instanceof Date + ? dateutil_clone(cached) + : cached; + }; + return Cache; +}()); + + +;// CONCATENATED MODULE: ./src/masks.ts + + +// ============================================================================= +// Date masks +// ============================================================================= +// Every mask is 7 days longer to handle cross-year weekly periods. +var M365MASK = __spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray([], repeat(1, 31), true), repeat(2, 28), true), repeat(3, 31), true), repeat(4, 30), true), repeat(5, 31), true), repeat(6, 30), true), repeat(7, 31), true), repeat(8, 31), true), repeat(9, 30), true), repeat(10, 31), true), repeat(11, 30), true), repeat(12, 31), true), repeat(1, 7), true); +var M366MASK = __spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray([], repeat(1, 31), true), repeat(2, 29), true), repeat(3, 31), true), repeat(4, 30), true), repeat(5, 31), true), repeat(6, 30), true), repeat(7, 31), true), repeat(8, 31), true), repeat(9, 30), true), repeat(10, 31), true), repeat(11, 30), true), repeat(12, 31), true), repeat(1, 7), true); +var M28 = range(1, 29); +var M29 = range(1, 30); +var M30 = range(1, 31); +var M31 = range(1, 32); +var MDAY366MASK = __spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray([], M31, true), M29, true), M31, true), M30, true), M31, true), M30, true), M31, true), M31, true), M30, true), M31, true), M30, true), M31, true), M31.slice(0, 7), true); +var MDAY365MASK = __spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray([], M31, true), M28, true), M31, true), M30, true), M31, true), M30, true), M31, true), M31, true), M30, true), M31, true), M30, true), M31, true), M31.slice(0, 7), true); +var NM28 = range(-28, 0); +var NM29 = range(-29, 0); +var NM30 = range(-30, 0); +var NM31 = range(-31, 0); +var NMDAY366MASK = __spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray([], NM31, true), NM29, true), NM31, true), NM30, true), NM31, true), NM30, true), NM31, true), NM31, true), NM30, true), NM31, true), NM30, true), NM31, true), NM31.slice(0, 7), true); +var NMDAY365MASK = __spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray(__spreadArray([], NM31, true), NM28, true), NM31, true), NM30, true), NM31, true), NM30, true), NM31, true), NM31, true), NM30, true), NM31, true), NM30, true), NM31, true), NM31.slice(0, 7), true); +var M366RANGE = [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366]; +var M365RANGE = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365]; +var WDAYMASK = (function () { + var wdaymask = []; + for (var i = 0; i < 55; i++) + wdaymask = wdaymask.concat(range(7)); + return wdaymask; +})(); + + +;// CONCATENATED MODULE: ./src/iterinfo/yearinfo.ts + + + + +function rebuildYear(year, options) { + var firstyday = datetime(year, 1, 1); + var yearlen = isLeapYear(year) ? 366 : 365; + var nextyearlen = isLeapYear(year + 1) ? 366 : 365; + var yearordinal = toOrdinal(firstyday); + var yearweekday = getWeekday(firstyday); + var result = __assign(__assign({ yearlen: yearlen, nextyearlen: nextyearlen, yearordinal: yearordinal, yearweekday: yearweekday }, baseYearMasks(year)), { wnomask: null }); + if (empty(options.byweekno)) { + return result; + } + result.wnomask = repeat(0, yearlen + 7); + var firstwkst; + var wyearlen; + var no1wkst = (firstwkst = pymod(7 - yearweekday + options.wkst, 7)); + if (no1wkst >= 4) { + no1wkst = 0; + // Number of days in the year, plus the days we got + // from last year. + wyearlen = result.yearlen + pymod(yearweekday - options.wkst, 7); + } + else { + // Number of days in the year, minus the days we + // left in last year. + wyearlen = yearlen - no1wkst; + } + var div = Math.floor(wyearlen / 7); + var mod = pymod(wyearlen, 7); + var numweeks = Math.floor(div + mod / 4); + for (var j = 0; j < options.byweekno.length; j++) { + var n = options.byweekno[j]; + if (n < 0) { + n += numweeks + 1; + } + if (!(n > 0 && n <= numweeks)) { + continue; + } + var i = void 0; + if (n > 1) { + i = no1wkst + (n - 1) * 7; + if (no1wkst !== firstwkst) { + i -= 7 - firstwkst; + } + } + else { + i = no1wkst; + } + for (var k = 0; k < 7; k++) { + result.wnomask[i] = 1; + i++; + if (result.wdaymask[i] === options.wkst) + break; + } + } + if (includes(options.byweekno, 1)) { + // Check week number 1 of next year as well + // orig-TODO : Check -numweeks for next year. + var i = no1wkst + numweeks * 7; + if (no1wkst !== firstwkst) + i -= 7 - firstwkst; + if (i < yearlen) { + // If week starts in next year, we + // don't care about it. + for (var j = 0; j < 7; j++) { + result.wnomask[i] = 1; + i += 1; + if (result.wdaymask[i] === options.wkst) + break; + } + } + } + if (no1wkst) { + // Check last week number of last year as + // well. If no1wkst is 0, either the year + // started on week start, or week number 1 + // got days from last year, so there are no + // days from last year's last week number in + // this year. + var lnumweeks = void 0; + if (!includes(options.byweekno, -1)) { + var lyearweekday = getWeekday(datetime(year - 1, 1, 1)); + var lno1wkst = pymod(7 - lyearweekday.valueOf() + options.wkst, 7); + var lyearlen = isLeapYear(year - 1) ? 366 : 365; + var weekst = void 0; + if (lno1wkst >= 4) { + lno1wkst = 0; + weekst = lyearlen + pymod(lyearweekday - options.wkst, 7); + } + else { + weekst = yearlen - no1wkst; + } + lnumweeks = Math.floor(52 + pymod(weekst, 7) / 4); + } + else { + lnumweeks = -1; + } + if (includes(options.byweekno, lnumweeks)) { + for (var i = 0; i < no1wkst; i++) + result.wnomask[i] = 1; + } + } + return result; +} +function baseYearMasks(year) { + var yearlen = isLeapYear(year) ? 366 : 365; + var firstyday = datetime(year, 1, 1); + var wday = getWeekday(firstyday); + if (yearlen === 365) { + return { + mmask: M365MASK, + mdaymask: MDAY365MASK, + nmdaymask: NMDAY365MASK, + wdaymask: WDAYMASK.slice(wday), + mrange: M365RANGE, + }; + } + return { + mmask: M366MASK, + mdaymask: MDAY366MASK, + nmdaymask: NMDAY366MASK, + wdaymask: WDAYMASK.slice(wday), + mrange: M366RANGE, + }; +} + +;// CONCATENATED MODULE: ./src/iterinfo/monthinfo.ts + + +function rebuildMonth(year, month, yearlen, mrange, wdaymask, options) { + var result = { + lastyear: year, + lastmonth: month, + nwdaymask: [], + }; + var ranges = []; + if (options.freq === RRule.YEARLY) { + if (empty(options.bymonth)) { + ranges = [[0, yearlen]]; + } + else { + for (var j = 0; j < options.bymonth.length; j++) { + month = options.bymonth[j]; + ranges.push(mrange.slice(month - 1, month + 1)); + } + } + } + else if (options.freq === RRule.MONTHLY) { + ranges = [mrange.slice(month - 1, month + 1)]; + } + if (empty(ranges)) { + return result; + } + // Weekly frequency won't get here, so we may not + // care about cross-year weekly periods. + result.nwdaymask = repeat(0, yearlen); + for (var j = 0; j < ranges.length; j++) { + var rang = ranges[j]; + var first = rang[0]; + var last = rang[1] - 1; + for (var k = 0; k < options.bynweekday.length; k++) { + var i = void 0; + var _a = options.bynweekday[k], wday = _a[0], n = _a[1]; + if (n < 0) { + i = last + (n + 1) * 7; + i -= pymod(wdaymask[i] - wday, 7); + } + else { + i = first + (n - 1) * 7; + i += pymod(7 - wdaymask[i] + wday, 7); + } + if (first <= i && i <= last) + result.nwdaymask[i] = 1; + } + } + return result; +} + +;// CONCATENATED MODULE: ./src/iterinfo/easter.ts +function easter(y, offset) { + if (offset === void 0) { offset = 0; } + var a = y % 19; + var b = Math.floor(y / 100); + var c = y % 100; + var d = Math.floor(b / 4); + var e = b % 4; + var f = Math.floor((b + 8) / 25); + var g = Math.floor((b - f + 1) / 3); + var h = Math.floor(19 * a + b - d - g + 15) % 30; + var i = Math.floor(c / 4); + var k = c % 4; + var l = Math.floor(32 + 2 * e + 2 * i - h - k) % 7; + var m = Math.floor((a + 11 * h + 22 * l) / 451); + var month = Math.floor((h + l - 7 * m + 114) / 31); + var day = ((h + l - 7 * m + 114) % 31) + 1; + var date = Date.UTC(y, month - 1, day + offset); + var yearStart = Date.UTC(y, 0, 1); + return [Math.ceil((date - yearStart) / (1000 * 60 * 60 * 24))]; +} + +;// CONCATENATED MODULE: ./src/iterinfo/index.ts + + + + + + + +// ============================================================================= +// Iterinfo +// ============================================================================= +var Iterinfo = /** @class */ (function () { + // eslint-disable-next-line no-empty-function + function Iterinfo(options) { + this.options = options; + } + Iterinfo.prototype.rebuild = function (year, month) { + var options = this.options; + if (year !== this.lastyear) { + this.yearinfo = rebuildYear(year, options); + } + if (notEmpty(options.bynweekday) && + (month !== this.lastmonth || year !== this.lastyear)) { + var _a = this.yearinfo, yearlen = _a.yearlen, mrange = _a.mrange, wdaymask = _a.wdaymask; + this.monthinfo = rebuildMonth(year, month, yearlen, mrange, wdaymask, options); + } + if (isPresent(options.byeaster)) { + this.eastermask = easter(year, options.byeaster); + } + }; + Object.defineProperty(Iterinfo.prototype, "lastyear", { + get: function () { + return this.monthinfo ? this.monthinfo.lastyear : null; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Iterinfo.prototype, "lastmonth", { + get: function () { + return this.monthinfo ? this.monthinfo.lastmonth : null; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Iterinfo.prototype, "yearlen", { + get: function () { + return this.yearinfo.yearlen; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Iterinfo.prototype, "yearordinal", { + get: function () { + return this.yearinfo.yearordinal; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Iterinfo.prototype, "mrange", { + get: function () { + return this.yearinfo.mrange; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Iterinfo.prototype, "wdaymask", { + get: function () { + return this.yearinfo.wdaymask; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Iterinfo.prototype, "mmask", { + get: function () { + return this.yearinfo.mmask; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Iterinfo.prototype, "wnomask", { + get: function () { + return this.yearinfo.wnomask; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Iterinfo.prototype, "nwdaymask", { + get: function () { + return this.monthinfo ? this.monthinfo.nwdaymask : []; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Iterinfo.prototype, "nextyearlen", { + get: function () { + return this.yearinfo.nextyearlen; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Iterinfo.prototype, "mdaymask", { + get: function () { + return this.yearinfo.mdaymask; + }, + enumerable: false, + configurable: true + }); + Object.defineProperty(Iterinfo.prototype, "nmdaymask", { + get: function () { + return this.yearinfo.nmdaymask; + }, + enumerable: false, + configurable: true + }); + Iterinfo.prototype.ydayset = function () { + return [range(this.yearlen), 0, this.yearlen]; + }; + Iterinfo.prototype.mdayset = function (_, month) { + var start = this.mrange[month - 1]; + var end = this.mrange[month]; + var set = repeat(null, this.yearlen); + for (var i = start; i < end; i++) + set[i] = i; + return [set, start, end]; + }; + Iterinfo.prototype.wdayset = function (year, month, day) { + // We need to handle cross-year weeks here. + var set = repeat(null, this.yearlen + 7); + var i = toOrdinal(datetime(year, month, day)) - this.yearordinal; + var start = i; + for (var j = 0; j < 7; j++) { + set[i] = i; + ++i; + if (this.wdaymask[i] === this.options.wkst) + break; + } + return [set, start, i]; + }; + Iterinfo.prototype.ddayset = function (year, month, day) { + var set = repeat(null, this.yearlen); + var i = toOrdinal(datetime(year, month, day)) - this.yearordinal; + set[i] = i; + return [set, i, i + 1]; + }; + Iterinfo.prototype.htimeset = function (hour, _, second, millisecond) { + var _this = this; + var set = []; + this.options.byminute.forEach(function (minute) { + set = set.concat(_this.mtimeset(hour, minute, second, millisecond)); + }); + sort(set); + return set; + }; + Iterinfo.prototype.mtimeset = function (hour, minute, _, millisecond) { + var set = this.options.bysecond.map(function (second) { return new Time(hour, minute, second, millisecond); }); + sort(set); + return set; + }; + Iterinfo.prototype.stimeset = function (hour, minute, second, millisecond) { + return [new Time(hour, minute, second, millisecond)]; + }; + Iterinfo.prototype.getdayset = function (freq) { + switch (freq) { + case Frequency.YEARLY: + return this.ydayset.bind(this); + case Frequency.MONTHLY: + return this.mdayset.bind(this); + case Frequency.WEEKLY: + return this.wdayset.bind(this); + case Frequency.DAILY: + return this.ddayset.bind(this); + default: + return this.ddayset.bind(this); + } + }; + Iterinfo.prototype.gettimeset = function (freq) { + switch (freq) { + case Frequency.HOURLY: + return this.htimeset.bind(this); + case Frequency.MINUTELY: + return this.mtimeset.bind(this); + case Frequency.SECONDLY: + return this.stimeset.bind(this); + } + }; + return Iterinfo; +}()); +/* harmony default export */ const iterinfo = (Iterinfo); + +;// CONCATENATED MODULE: ./src/iter/poslist.ts + + +function buildPoslist(bysetpos, timeset, start, end, ii, dayset) { + var poslist = []; + for (var j = 0; j < bysetpos.length; j++) { + var daypos = void 0; + var timepos = void 0; + var pos = bysetpos[j]; + if (pos < 0) { + daypos = Math.floor(pos / timeset.length); + timepos = pymod(pos, timeset.length); + } + else { + daypos = Math.floor((pos - 1) / timeset.length); + timepos = pymod(pos - 1, timeset.length); + } + var tmp = []; + for (var k = start; k < end; k++) { + var val = dayset[k]; + if (!isPresent(val)) + continue; + tmp.push(val); + } + var i = void 0; + if (daypos < 0) { + i = tmp.slice(daypos)[0]; + } + else { + i = tmp[daypos]; + } + var time = timeset[timepos]; + var date = fromOrdinal(ii.yearordinal + i); + var res = combine(date, time); + // XXX: can this ever be in the array? + // - compare the actual date instead? + if (!includes(poslist, res)) + poslist.push(res); + } + sort(poslist); + return poslist; +} + +;// CONCATENATED MODULE: ./src/iter/index.ts + + + + + + + + + +function iter(iterResult, options) { + var dtstart = options.dtstart, freq = options.freq, interval = options.interval, until = options.until, bysetpos = options.bysetpos; + var count = options.count; + if (count === 0 || interval === 0) { + return emitResult(iterResult); + } + var counterDate = DateTime.fromDate(dtstart); + var ii = new iterinfo(options); + ii.rebuild(counterDate.year, counterDate.month); + var timeset = makeTimeset(ii, counterDate, options); + for (;;) { + var _a = ii.getdayset(freq)(counterDate.year, counterDate.month, counterDate.day), dayset = _a[0], start = _a[1], end = _a[2]; + var filtered = removeFilteredDays(dayset, start, end, ii, options); + if (notEmpty(bysetpos)) { + var poslist = buildPoslist(bysetpos, timeset, start, end, ii, dayset); + for (var j = 0; j < poslist.length; j++) { + var res = poslist[j]; + if (until && res > until) { + return emitResult(iterResult); + } + if (res >= dtstart) { + var rezonedDate = rezoneIfNeeded(res, options); + if (!iterResult.accept(rezonedDate)) { + return emitResult(iterResult); + } + if (count) { + --count; + if (!count) { + return emitResult(iterResult); + } + } + } + } + } + else { + for (var j = start; j < end; j++) { + var currentDay = dayset[j]; + if (!isPresent(currentDay)) { + continue; + } + var date = fromOrdinal(ii.yearordinal + currentDay); + for (var k = 0; k < timeset.length; k++) { + var time = timeset[k]; + var res = combine(date, time); + if (until && res > until) { + return emitResult(iterResult); + } + if (res >= dtstart) { + var rezonedDate = rezoneIfNeeded(res, options); + if (!iterResult.accept(rezonedDate)) { + return emitResult(iterResult); + } + if (count) { + --count; + if (!count) { + return emitResult(iterResult); + } + } + } + } + } + } + if (options.interval === 0) { + return emitResult(iterResult); + } + // Handle frequency and interval + counterDate.add(options, filtered); + if (counterDate.year > MAXYEAR) { + return emitResult(iterResult); + } + if (!freqIsDailyOrGreater(freq)) { + timeset = ii.gettimeset(freq)(counterDate.hour, counterDate.minute, counterDate.second, 0); + } + ii.rebuild(counterDate.year, counterDate.month); + } +} +function isFiltered(ii, currentDay, options) { + var bymonth = options.bymonth, byweekno = options.byweekno, byweekday = options.byweekday, byeaster = options.byeaster, bymonthday = options.bymonthday, bynmonthday = options.bynmonthday, byyearday = options.byyearday; + return ((notEmpty(bymonth) && !includes(bymonth, ii.mmask[currentDay])) || + (notEmpty(byweekno) && !ii.wnomask[currentDay]) || + (notEmpty(byweekday) && !includes(byweekday, ii.wdaymask[currentDay])) || + (notEmpty(ii.nwdaymask) && !ii.nwdaymask[currentDay]) || + (byeaster !== null && !includes(ii.eastermask, currentDay)) || + ((notEmpty(bymonthday) || notEmpty(bynmonthday)) && + !includes(bymonthday, ii.mdaymask[currentDay]) && + !includes(bynmonthday, ii.nmdaymask[currentDay])) || + (notEmpty(byyearday) && + ((currentDay < ii.yearlen && + !includes(byyearday, currentDay + 1) && + !includes(byyearday, -ii.yearlen + currentDay)) || + (currentDay >= ii.yearlen && + !includes(byyearday, currentDay + 1 - ii.yearlen) && + !includes(byyearday, -ii.nextyearlen + currentDay - ii.yearlen))))); +} +function rezoneIfNeeded(date, options) { + return new DateWithZone(date, options.tzid).rezonedDate(); +} +function emitResult(iterResult) { + return iterResult.getValue(); +} +function removeFilteredDays(dayset, start, end, ii, options) { + var filtered = false; + for (var dayCounter = start; dayCounter < end; dayCounter++) { + var currentDay = dayset[dayCounter]; + filtered = isFiltered(ii, currentDay, options); + if (filtered) + dayset[currentDay] = null; + } + return filtered; +} +function makeTimeset(ii, counterDate, options) { + var freq = options.freq, byhour = options.byhour, byminute = options.byminute, bysecond = options.bysecond; + if (freqIsDailyOrGreater(freq)) { + return buildTimeset(options); + } + if ((freq >= RRule.HOURLY && + notEmpty(byhour) && + !includes(byhour, counterDate.hour)) || + (freq >= RRule.MINUTELY && + notEmpty(byminute) && + !includes(byminute, counterDate.minute)) || + (freq >= RRule.SECONDLY && + notEmpty(bysecond) && + !includes(bysecond, counterDate.second))) { + return []; + } + return ii.gettimeset(freq)(counterDate.hour, counterDate.minute, counterDate.second, counterDate.millisecond); +} + +;// CONCATENATED MODULE: ./src/rrule.ts + + + + + + + + + + + +// ============================================================================= +// RRule +// ============================================================================= +var Days = { + MO: new Weekday(0), + TU: new Weekday(1), + WE: new Weekday(2), + TH: new Weekday(3), + FR: new Weekday(4), + SA: new Weekday(5), + SU: new Weekday(6), +}; +var DEFAULT_OPTIONS = { + freq: Frequency.YEARLY, + dtstart: null, + interval: 1, + wkst: Days.MO, + count: null, + until: null, + tzid: null, + bysetpos: null, + bymonth: null, + bymonthday: null, + bynmonthday: null, + byyearday: null, + byweekno: null, + byweekday: null, + bynweekday: null, + byhour: null, + byminute: null, + bysecond: null, + byeaster: null, +}; +var defaultKeys = Object.keys(DEFAULT_OPTIONS); +/** + * + * @param {Options?} options - see + * - The only required option is `freq`, one of RRule.YEARLY, RRule.MONTHLY, ... + * @constructor + */ +var RRule = /** @class */ (function () { + function RRule(options, noCache) { + if (options === void 0) { options = {}; } + if (noCache === void 0) { noCache = false; } + // RFC string + this._cache = noCache ? null : new Cache(); + // used by toString() + this.origOptions = initializeOptions(options); + var parsedOptions = parseOptions(options).parsedOptions; + this.options = parsedOptions; + } + RRule.parseText = function (text, language) { + return parseText(text, language); + }; + RRule.fromText = function (text, language) { + return fromText(text, language); + }; + RRule.fromString = function (str) { + return new RRule(RRule.parseString(str) || undefined); + }; + RRule.prototype._iter = function (iterResult) { + return iter(iterResult, this.options); + }; + RRule.prototype._cacheGet = function (what, args) { + if (!this._cache) + return false; + return this._cache._cacheGet(what, args); + }; + RRule.prototype._cacheAdd = function (what, value, args) { + if (!this._cache) + return; + return this._cache._cacheAdd(what, value, args); + }; + /** + * @param {Function} iterator - optional function that will be called + * on each date that is added. It can return false + * to stop the iteration. + * @return Array containing all recurrences. + */ + RRule.prototype.all = function (iterator) { + if (iterator) { + return this._iter(new callbackiterresult('all', {}, iterator)); + } + var result = this._cacheGet('all'); + if (result === false) { + result = this._iter(new iterresult('all', {})); + this._cacheAdd('all', result); + } + return result; + }; + /** + * Returns all the occurrences of the rrule between after and before. + * The inc keyword defines what happens if after and/or before are + * themselves occurrences. With inc == True, they will be included in the + * list, if they are found in the recurrence set. + * + * @return Array + */ + RRule.prototype.between = function (after, before, inc, iterator) { + if (inc === void 0) { inc = false; } + if (!isValidDate(after) || !isValidDate(before)) { + throw new Error('Invalid date passed in to RRule.between'); + } + var args = { + before: before, + after: after, + inc: inc, + }; + if (iterator) { + return this._iter(new callbackiterresult('between', args, iterator)); + } + var result = this._cacheGet('between', args); + if (result === false) { + result = this._iter(new iterresult('between', args)); + this._cacheAdd('between', result, args); + } + return result; + }; + /** + * Returns the last recurrence before the given datetime instance. + * The inc keyword defines what happens if dt is an occurrence. + * With inc == True, if dt itself is an occurrence, it will be returned. + * + * @return Date or null + */ + RRule.prototype.before = function (dt, inc) { + if (inc === void 0) { inc = false; } + if (!isValidDate(dt)) { + throw new Error('Invalid date passed in to RRule.before'); + } + var args = { dt: dt, inc: inc }; + var result = this._cacheGet('before', args); + if (result === false) { + result = this._iter(new iterresult('before', args)); + this._cacheAdd('before', result, args); + } + return result; + }; + /** + * Returns the first recurrence after the given datetime instance. + * The inc keyword defines what happens if dt is an occurrence. + * With inc == True, if dt itself is an occurrence, it will be returned. + * + * @return Date or null + */ + RRule.prototype.after = function (dt, inc) { + if (inc === void 0) { inc = false; } + if (!isValidDate(dt)) { + throw new Error('Invalid date passed in to RRule.after'); + } + var args = { dt: dt, inc: inc }; + var result = this._cacheGet('after', args); + if (result === false) { + result = this._iter(new iterresult('after', args)); + this._cacheAdd('after', result, args); + } + return result; + }; + /** + * Returns the number of recurrences in this set. It will have go trough + * the whole recurrence, if this hasn't been done before. + */ + RRule.prototype.count = function () { + return this.all().length; + }; + /** + * Converts the rrule into its string representation + * + * @see + * @return String + */ + RRule.prototype.toString = function () { + return optionsToString(this.origOptions); + }; + /** + * Will convert all rules described in nlp:ToText + * to text. + */ + RRule.prototype.toText = function (gettext, language, dateFormatter) { + return toText(this, gettext, language, dateFormatter); + }; + RRule.prototype.isFullyConvertibleToText = function () { + return isFullyConvertible(this); + }; + /** + * @return a RRule instance with the same freq and options + * as this one (cache is not cloned) + */ + RRule.prototype.clone = function () { + return new RRule(this.origOptions); + }; + // RRule class 'constants' + RRule.FREQUENCIES = [ + 'YEARLY', + 'MONTHLY', + 'WEEKLY', + 'DAILY', + 'HOURLY', + 'MINUTELY', + 'SECONDLY', + ]; + RRule.YEARLY = Frequency.YEARLY; + RRule.MONTHLY = Frequency.MONTHLY; + RRule.WEEKLY = Frequency.WEEKLY; + RRule.DAILY = Frequency.DAILY; + RRule.HOURLY = Frequency.HOURLY; + RRule.MINUTELY = Frequency.MINUTELY; + RRule.SECONDLY = Frequency.SECONDLY; + RRule.MO = Days.MO; + RRule.TU = Days.TU; + RRule.WE = Days.WE; + RRule.TH = Days.TH; + RRule.FR = Days.FR; + RRule.SA = Days.SA; + RRule.SU = Days.SU; + RRule.parseString = parseString; + RRule.optionsToString = optionsToString; + return RRule; +}()); + + +;// CONCATENATED MODULE: ./src/iterset.ts + + + +function iterSet(iterResult, _rrule, _exrule, _rdate, _exdate, tzid) { + var _exdateHash = {}; + var _accept = iterResult.accept; + function evalExdate(after, before) { + _exrule.forEach(function (rrule) { + rrule.between(after, before, true).forEach(function (date) { + _exdateHash[Number(date)] = true; + }); + }); + } + _exdate.forEach(function (date) { + var zonedDate = new DateWithZone(date, tzid).rezonedDate(); + _exdateHash[Number(zonedDate)] = true; + }); + iterResult.accept = function (date) { + var dt = Number(date); + if (isNaN(dt)) + return _accept.call(this, date); + if (!_exdateHash[dt]) { + evalExdate(new Date(dt - 1), new Date(dt + 1)); + if (!_exdateHash[dt]) { + _exdateHash[dt] = true; + return _accept.call(this, date); + } + } + return true; + }; + if (iterResult.method === 'between') { + evalExdate(iterResult.args.after, iterResult.args.before); + iterResult.accept = function (date) { + var dt = Number(date); + if (!_exdateHash[dt]) { + _exdateHash[dt] = true; + return _accept.call(this, date); + } + return true; + }; + } + for (var i = 0; i < _rdate.length; i++) { + var zonedDate = new DateWithZone(_rdate[i], tzid).rezonedDate(); + if (!iterResult.accept(new Date(zonedDate.getTime()))) + break; + } + _rrule.forEach(function (rrule) { + iter(iterResult, rrule.options); + }); + var res = iterResult._result; + sort(res); + switch (iterResult.method) { + case 'all': + case 'between': + return res; + case 'before': + return ((res.length && res[res.length - 1]) || null); + case 'after': + default: + return ((res.length && res[0]) || null); + } +} + +;// CONCATENATED MODULE: ./src/rrulestr.ts + + + + + + +/** + * RRuleStr + * To parse a set of rrule strings + */ +var rrulestr_DEFAULT_OPTIONS = { + dtstart: null, + cache: false, + unfold: false, + forceset: false, + compatible: false, + tzid: null, +}; +function parseInput(s, options) { + var rrulevals = []; + var rdatevals = []; + var exrulevals = []; + var exdatevals = []; + var parsedDtstart = parseDtstart(s); + var dtstart = parsedDtstart.dtstart; + var tzid = parsedDtstart.tzid; + var lines = splitIntoLines(s, options.unfold); + lines.forEach(function (line) { + var _a; + if (!line) + return; + var _b = breakDownLine(line), name = _b.name, parms = _b.parms, value = _b.value; + switch (name.toUpperCase()) { + case 'RRULE': + if (parms.length) { + throw new Error("unsupported RRULE parm: ".concat(parms.join(','))); + } + rrulevals.push(parseString(line)); + break; + case 'RDATE': + var _c = (_a = /RDATE(?:;TZID=([^:=]+))?/i.exec(line)) !== null && _a !== void 0 ? _a : [], rdateTzid = _c[1]; + if (rdateTzid && !tzid) { + tzid = rdateTzid; + } + rdatevals = rdatevals.concat(parseRDate(value, parms)); + break; + case 'EXRULE': + if (parms.length) { + throw new Error("unsupported EXRULE parm: ".concat(parms.join(','))); + } + exrulevals.push(parseString(value)); + break; + case 'EXDATE': + exdatevals = exdatevals.concat(parseRDate(value, parms)); + break; + case 'DTSTART': + break; + default: + throw new Error('unsupported property: ' + name); + } + }); + return { + dtstart: dtstart, + tzid: tzid, + rrulevals: rrulevals, + rdatevals: rdatevals, + exrulevals: exrulevals, + exdatevals: exdatevals, + }; +} +function buildRule(s, options) { + var _a = parseInput(s, options), rrulevals = _a.rrulevals, rdatevals = _a.rdatevals, exrulevals = _a.exrulevals, exdatevals = _a.exdatevals, dtstart = _a.dtstart, tzid = _a.tzid; + var noCache = options.cache === false; + if (options.compatible) { + options.forceset = true; + options.unfold = true; + } + if (options.forceset || + rrulevals.length > 1 || + rdatevals.length || + exrulevals.length || + exdatevals.length) { + var rset_1 = new RRuleSet(noCache); + rset_1.dtstart(dtstart); + rset_1.tzid(tzid || undefined); + rrulevals.forEach(function (val) { + rset_1.rrule(new RRule(groomRruleOptions(val, dtstart, tzid), noCache)); + }); + rdatevals.forEach(function (date) { + rset_1.rdate(date); + }); + exrulevals.forEach(function (val) { + rset_1.exrule(new RRule(groomRruleOptions(val, dtstart, tzid), noCache)); + }); + exdatevals.forEach(function (date) { + rset_1.exdate(date); + }); + if (options.compatible && options.dtstart) + rset_1.rdate(dtstart); + return rset_1; + } + var val = rrulevals[0] || {}; + return new RRule(groomRruleOptions(val, val.dtstart || options.dtstart || dtstart, val.tzid || options.tzid || tzid), noCache); +} +function rrulestr(s, options) { + if (options === void 0) { options = {}; } + return buildRule(s, rrulestr_initializeOptions(options)); +} +function groomRruleOptions(val, dtstart, tzid) { + return __assign(__assign({}, val), { dtstart: dtstart, tzid: tzid }); +} +function rrulestr_initializeOptions(options) { + var invalid = []; + var keys = Object.keys(options); + var defaultKeys = Object.keys(rrulestr_DEFAULT_OPTIONS); + keys.forEach(function (key) { + if (!includes(defaultKeys, key)) + invalid.push(key); + }); + if (invalid.length) { + throw new Error('Invalid options: ' + invalid.join(', ')); + } + return __assign(__assign({}, rrulestr_DEFAULT_OPTIONS), options); +} +function extractName(line) { + if (line.indexOf(':') === -1) { + return { + name: 'RRULE', + value: line, + }; + } + var _a = split(line, ':', 1), name = _a[0], value = _a[1]; + return { + name: name, + value: value, + }; +} +function breakDownLine(line) { + var _a = extractName(line), name = _a.name, value = _a.value; + var parms = name.split(';'); + if (!parms) + throw new Error('empty property name'); + return { + name: parms[0].toUpperCase(), + parms: parms.slice(1), + value: value, + }; +} +function splitIntoLines(s, unfold) { + if (unfold === void 0) { unfold = false; } + s = s && s.trim(); + if (!s) + throw new Error('Invalid empty string'); + // More info about 'unfold' option + // Go head to http://www.ietf.org/rfc/rfc2445.txt + if (!unfold) { + return s.split(/\s/); + } + var lines = s.split('\n'); + var i = 0; + while (i < lines.length) { + // TODO + var line = (lines[i] = lines[i].replace(/\s+$/g, '')); + if (!line) { + lines.splice(i, 1); + } + else if (i > 0 && line[0] === ' ') { + lines[i - 1] += line.slice(1); + lines.splice(i, 1); + } + else { + i += 1; + } + } + return lines; +} +function validateDateParm(parms) { + parms.forEach(function (parm) { + if (!/(VALUE=DATE(-TIME)?)|(TZID=)/.test(parm)) { + throw new Error('unsupported RDATE/EXDATE parm: ' + parm); + } + }); +} +function parseRDate(rdateval, parms) { + validateDateParm(parms); + return rdateval.split(',').map(function (datestr) { return untilStringToDate(datestr); }); +} + +;// CONCATENATED MODULE: ./src/rruleset.ts + + + + + + + +function createGetterSetter(fieldName) { + var _this = this; + return function (field) { + if (field !== undefined) { + _this["_".concat(fieldName)] = field; + } + if (_this["_".concat(fieldName)] !== undefined) { + return _this["_".concat(fieldName)]; + } + for (var i = 0; i < _this._rrule.length; i++) { + var field_1 = _this._rrule[i].origOptions[fieldName]; + if (field_1) { + return field_1; + } + } + }; +} +var RRuleSet = /** @class */ (function (_super) { + __extends(RRuleSet, _super); + /** + * + * @param {Boolean?} noCache + * The same stratagy as RRule on cache, default to false + * @constructor + */ + function RRuleSet(noCache) { + if (noCache === void 0) { noCache = false; } + var _this = _super.call(this, {}, noCache) || this; + _this.dtstart = createGetterSetter.apply(_this, ['dtstart']); + _this.tzid = createGetterSetter.apply(_this, ['tzid']); + _this._rrule = []; + _this._rdate = []; + _this._exrule = []; + _this._exdate = []; + return _this; + } + RRuleSet.prototype._iter = function (iterResult) { + return iterSet(iterResult, this._rrule, this._exrule, this._rdate, this._exdate, this.tzid()); + }; + /** + * Adds an RRule to the set + * + * @param {RRule} + */ + RRuleSet.prototype.rrule = function (rrule) { + _addRule(rrule, this._rrule); + }; + /** + * Adds an EXRULE to the set + * + * @param {RRule} + */ + RRuleSet.prototype.exrule = function (rrule) { + _addRule(rrule, this._exrule); + }; + /** + * Adds an RDate to the set + * + * @param {Date} + */ + RRuleSet.prototype.rdate = function (date) { + _addDate(date, this._rdate); + }; + /** + * Adds an EXDATE to the set + * + * @param {Date} + */ + RRuleSet.prototype.exdate = function (date) { + _addDate(date, this._exdate); + }; + /** + * Get list of included rrules in this recurrence set. + * + * @return List of rrules + */ + RRuleSet.prototype.rrules = function () { + return this._rrule.map(function (e) { return rrulestr(e.toString()); }); + }; + /** + * Get list of excluded rrules in this recurrence set. + * + * @return List of exrules + */ + RRuleSet.prototype.exrules = function () { + return this._exrule.map(function (e) { return rrulestr(e.toString()); }); + }; + /** + * Get list of included datetimes in this recurrence set. + * + * @return List of rdates + */ + RRuleSet.prototype.rdates = function () { + return this._rdate.map(function (e) { return new Date(e.getTime()); }); + }; + /** + * Get list of included datetimes in this recurrence set. + * + * @return List of exdates + */ + RRuleSet.prototype.exdates = function () { + return this._exdate.map(function (e) { return new Date(e.getTime()); }); + }; + RRuleSet.prototype.valueOf = function () { + var result = []; + if (!this._rrule.length && this._dtstart) { + result = result.concat(optionsToString({ dtstart: this._dtstart })); + } + this._rrule.forEach(function (rrule) { + result = result.concat(rrule.toString().split('\n')); + }); + this._exrule.forEach(function (exrule) { + result = result.concat(exrule + .toString() + .split('\n') + .map(function (line) { return line.replace(/^RRULE:/, 'EXRULE:'); }) + .filter(function (line) { return !/^DTSTART/.test(line); })); + }); + if (this._rdate.length) { + result.push(rdatesToString('RDATE', this._rdate, this.tzid())); + } + if (this._exdate.length) { + result.push(rdatesToString('EXDATE', this._exdate, this.tzid())); + } + return result; + }; + /** + * to generate recurrence field such as: + * DTSTART:19970902T010000Z + * RRULE:FREQ=YEARLY;COUNT=2;BYDAY=TU + * RRULE:FREQ=YEARLY;COUNT=1;BYDAY=TH + */ + RRuleSet.prototype.toString = function () { + return this.valueOf().join('\n'); + }; + /** + * Create a new RRuleSet Object completely base on current instance + */ + RRuleSet.prototype.clone = function () { + var rrs = new RRuleSet(!!this._cache); + this._rrule.forEach(function (rule) { return rrs.rrule(rule.clone()); }); + this._exrule.forEach(function (rule) { return rrs.exrule(rule.clone()); }); + this._rdate.forEach(function (date) { return rrs.rdate(new Date(date.getTime())); }); + this._exdate.forEach(function (date) { return rrs.exdate(new Date(date.getTime())); }); + return rrs; + }; + return RRuleSet; +}(RRule)); + +function _addRule(rrule, collection) { + if (!(rrule instanceof RRule)) { + throw new TypeError(String(rrule) + ' is not RRule instance'); + } + if (!includes(collection.map(String), String(rrule))) { + collection.push(rrule); + } +} +function _addDate(date, collection) { + if (!(date instanceof Date)) { + throw new TypeError(String(date) + ' is not Date instance'); + } + if (!includes(collection.map(Number), Number(date))) { + collection.push(date); + sort(collection); + } +} +function rdatesToString(param, rdates, tzid) { + var isUTC = !tzid || tzid.toUpperCase() === 'UTC'; + var header = isUTC ? "".concat(param, ":") : "".concat(param, ";TZID=").concat(tzid, ":"); + var dateString = rdates + .map(function (rdate) { return timeToUntilString(rdate.valueOf(), isUTC); }) + .join(','); + return "".concat(header).concat(dateString); +} + +;// CONCATENATED MODULE: ./src/index.ts +/* ! + * rrule.js - Library for working with recurrence rules for calendar dates. + * https://github.com/jakubroztocil/rrule + * + * Copyright 2010, Jakub Roztocil and Lars Schoning + * Licenced under the BSD licence. + * https://github.com/jakubroztocil/rrule/blob/master/LICENCE + * + * Based on: + * python-dateutil - Extensions to the standard Python datetime module. + * Copyright (c) 2003-2011 - Gustavo Niemeyer + * Copyright (c) 2012 - Tomi Pieviläinen + * https://github.com/jakubroztocil/rrule/blob/master/LICENCE + * + */ + + + + + + + +/******/ return __webpack_exports__; +/******/ })() +; +}); \ No newline at end of file diff --git a/ephios/static/rrule/rrule.min.js b/ephios/static/rrule/rrule.min.js new file mode 100644 index 000000000..5416e5e14 --- /dev/null +++ b/ephios/static/rrule/rrule.min.js @@ -0,0 +1,2 @@ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.rrule=e():t.rrule=e()}("undefined"!=typeof self?self:this,(()=>(()=>{"use strict";var t={d:(e,n)=>{for(var r in n)t.o(n,r)&&!t.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:n[r]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e),r:t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})}},e={};t.r(e),t.d(e,{ALL_WEEKDAYS:()=>n,Frequency:()=>Z,RRule:()=>Pt,RRuleSet:()=>Gt,Weekday:()=>r,datetime:()=>b,rrulestr:()=>Kt});var n=["MO","TU","WE","TH","FR","SA","SU"],r=function(){function t(t,e){if(0===e)throw new Error("Can't create weekday with n == 0");this.weekday=t,this.n=e}return t.fromStr=function(e){return new t(n.indexOf(e))},t.prototype.nth=function(e){return this.n===e?this:new t(this.weekday,e)},t.prototype.equals=function(t){return this.weekday===t.weekday&&this.n===t.n},t.prototype.toString=function(){var t=n[this.weekday];return this.n&&(t=(this.n>0?"+":"")+String(this.n)+t),t},t.prototype.getJsWeekday=function(){return 6===this.weekday?0:this.weekday+1},t}(),i=function(t){return null!=t},o=function(t){return"number"==typeof t},a=function(t){return"string"==typeof t&&n.includes(t)},s=Array.isArray,u=function(t,e){void 0===e&&(e=t),1===arguments.length&&(e=t,t=0);for(var n=[],r=t;r>=0,r.length>e?String(r):((e-=r.length)>n.length&&(n+=h(n,e/n.length)),n.slice(0,e)+String(r))}var c=function(t,e){var n=t%e;return n*e<0?n+e:n},d=function(t,e){return{div:Math.floor(t/e),mod:c(t,e)}},l=function(t){return!i(t)||0===t.length},f=function(t){return!l(t)},p=function(t,e){return f(t)&&-1!==t.indexOf(e)},b=function(t,e,n,r,i,o){return void 0===r&&(r=0),void 0===i&&(i=0),void 0===o&&(o=0),new Date(Date.UTC(t,e-1,n,r,i,o))},m=[31,28,31,30,31,30,31,31,30,31,30,31],w=864e5,v=b(1970,1,1),g=[6,0,1,2,3,4,5],k=function(t){return t%4==0&&t%100!=0||t%400==0},E=function(t){return t instanceof Date},T=function(t){return E(t)&&!isNaN(t.getTime())},x=function(t){return e=v,n=t.getTime()-e.getTime(),Math.round(n/w);var e,n},D=function(t){return new Date(v.getTime()+t*w)},O=function(t){var e=t.getUTCMonth();return 1===e&&k(t.getUTCFullYear())?29:m[e]},S=function(t){return g[t.getUTCDay()]},U=function(t,e){var n=b(t,e+1,1);return[S(n),O(n)]},Y=function(t,e){return e=e||t,new Date(Date.UTC(t.getUTCFullYear(),t.getUTCMonth(),t.getUTCDate(),e.getHours(),e.getMinutes(),e.getSeconds(),e.getMilliseconds()))},L=function(t){return new Date(t.getTime())},M=function(t){for(var e=[],n=0;nthis.maxDate;if("between"===this.method){if(e)return!0;if(n)return!1}else if("before"===this.method){if(n)return!1}else if("after"===this.method)return!!e||(this.add(t),!1);return this.add(t)},t.prototype.add=function(t){return this._result.push(t),!0},t.prototype.getValue=function(){var t=this._result;switch(this.method){case"all":case"between":return t;default:return t.length?t[t.length-1]:null}},t.prototype.clone=function(){return new t(this.method,this.args)},t}();var I=function(t,e){return I=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n])},I(t,e)};function j(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Class extends value "+String(e)+" is not a constructor or null");function n(){this.constructor=t}I(t,e),t.prototype=null===e?Object.create(e):(n.prototype=e.prototype,new n)}var W=function(){return W=Object.assign||function(t){for(var e,n=1,r=arguments.length;nt[0].length)&&(t=r,e=n)}if(null!=t&&(this.text=this.text.substr(t[0].length),""===this.text&&(this.done=!0)),null==t)return this.done=!0,this.symbol=null,void(this.value=null)}while("SKIP"===e);return this.symbol=e,this.value=t,!0},t.prototype.accept=function(t){if(this.symbol===t){if(this.value){var e=this.value;return this.nextSymbol(),e}return this.nextSymbol(),!0}return!1},t.prototype.acceptNumber=function(){return this.accept("number")},t.prototype.expect=function(t){if(this.accept(t))return!0;throw new Error("expected "+t+" but found "+this.symbol)},t}();function G(t,e){void 0===e&&(e=P);var n={},r=new X(e.tokens);return r.start(t)?(function(){r.expect("every");var t=r.acceptNumber();t&&(n.interval=parseInt(t[0],10));if(r.isDone())throw new Error("Unexpected end");switch(r.symbol){case"day(s)":n.freq=Pt.DAILY,r.nextSymbol()&&(o(),h());break;case"weekday(s)":n.freq=Pt.WEEKLY,n.byweekday=[Pt.MO,Pt.TU,Pt.WE,Pt.TH,Pt.FR],r.nextSymbol(),o(),h();break;case"week(s)":n.freq=Pt.WEEKLY,r.nextSymbol()&&(i(),o(),h());break;case"hour(s)":n.freq=Pt.HOURLY,r.nextSymbol()&&(i(),h());break;case"minute(s)":n.freq=Pt.MINUTELY,r.nextSymbol()&&(i(),h());break;case"month(s)":n.freq=Pt.MONTHLY,r.nextSymbol()&&(i(),h());break;case"year(s)":n.freq=Pt.YEARLY,r.nextSymbol()&&(i(),h());break;case"monday":case"tuesday":case"wednesday":case"thursday":case"friday":case"saturday":case"sunday":n.freq=Pt.WEEKLY;var e=r.symbol.substr(0,2).toUpperCase();if(n.byweekday=[Pt[e]],!r.nextSymbol())return;for(;r.accept("comma");){if(r.isDone())throw new Error("Unexpected end");var y=s();if(!y)throw new Error("Unexpected symbol "+r.symbol+", expected weekday");n.byweekday.push(Pt[y]),r.nextSymbol()}o(),function(){r.accept("on"),r.accept("the");var t=u();if(!t)return;n.bymonthday=[t],r.nextSymbol();for(;r.accept("comma");){if(!(t=u()))throw new Error("Unexpected symbol "+r.symbol+"; expected monthday");n.bymonthday.push(t),r.nextSymbol()}}(),h();break;case"january":case"february":case"march":case"april":case"may":case"june":case"july":case"august":case"september":case"october":case"november":case"december":if(n.freq=Pt.YEARLY,n.bymonth=[a()],!r.nextSymbol())return;for(;r.accept("comma");){if(r.isDone())throw new Error("Unexpected end");var c=a();if(!c)throw new Error("Unexpected symbol "+r.symbol+", expected month");n.bymonth.push(c),r.nextSymbol()}i(),h();break;default:throw new Error("Unknown symbol")}}(),n):null;function i(){var t=r.accept("on"),e=r.accept("the");if(t||e)do{var i=u(),o=s(),h=a();if(i)o?(r.nextSymbol(),n.byweekday||(n.byweekday=[]),n.byweekday.push(Pt[o].nth(i))):(n.bymonthday||(n.bymonthday=[]),n.bymonthday.push(i),r.accept("day(s)"));else if(o)r.nextSymbol(),n.byweekday||(n.byweekday=[]),n.byweekday.push(Pt[o]);else if("weekday(s)"===r.symbol)r.nextSymbol(),n.byweekday||(n.byweekday=[Pt.MO,Pt.TU,Pt.WE,Pt.TH,Pt.FR]);else if("week(s)"===r.symbol){r.nextSymbol();var y=r.acceptNumber();if(!y)throw new Error("Unexpected symbol "+r.symbol+", expected week number");for(n.byweekno=[parseInt(y[0],10)];r.accept("comma");){if(!(y=r.acceptNumber()))throw new Error("Unexpected symbol "+r.symbol+"; expected monthday");n.byweekno.push(parseInt(y[0],10))}}else{if(!h)return;r.nextSymbol(),n.bymonth||(n.bymonth=[]),n.bymonth.push(h)}}while(r.accept("comma")||r.accept("the")||r.accept("on"))}function o(){if(r.accept("at"))do{var t=r.acceptNumber();if(!t)throw new Error("Unexpected symbol "+r.symbol+", expected hour");for(n.byhour=[parseInt(t[0],10)];r.accept("comma");){if(!(t=r.acceptNumber()))throw new Error("Unexpected symbol "+r.symbol+"; expected hour");n.byhour.push(parseInt(t[0],10))}}while(r.accept("comma")||r.accept("at"))}function a(){switch(r.symbol){case"january":return 1;case"february":return 2;case"march":return 3;case"april":return 4;case"may":return 5;case"june":return 6;case"july":return 7;case"august":return 8;case"september":return 9;case"october":return 10;case"november":return 11;case"december":return 12;default:return!1}}function s(){switch(r.symbol){case"monday":case"tuesday":case"wednesday":case"thursday":case"friday":case"saturday":case"sunday":return r.symbol.substr(0,2).toUpperCase();default:return!1}}function u(){switch(r.symbol){case"last":return r.nextSymbol(),-1;case"first":return r.nextSymbol(),1;case"second":return r.nextSymbol(),r.accept("last")?-2:2;case"third":return r.nextSymbol(),r.accept("last")?-3:3;case"nth":var t=parseInt(r.value[1],10);if(t<-366||t>366)throw new Error("Nth out of range: "+t);return r.nextSymbol(),r.accept("last")?-t:t;default:return!1}}function h(){if("until"===r.symbol){var t=Date.parse(r.text);if(!t)throw new Error("Cannot parse until date:"+r.text);n.until=new Date(t)}else r.accept("for")&&(n.count=parseInt(r.value[0],10),r.expect("number"))}}function Q(t){return t12){var e=Math.floor(this.month/12),n=c(this.month,12);this.month=n,this.year+=e,0===this.month&&(this.month=12,--this.year)}},e.prototype.addWeekly=function(t,e){e>this.getWeekday()?this.day+=-(this.getWeekday()+1+(6-e))+7*t:this.day+=-(this.getWeekday()-e)+7*t,this.fixDay()},e.prototype.addDaily=function(t){this.day+=t,this.fixDay()},e.prototype.addHours=function(t,e,n){for(e&&(this.hour+=Math.floor((23-this.hour)/t)*t);;){this.hour+=t;var r=d(this.hour,24),i=r.div,o=r.mod;if(i&&(this.hour=o,this.addDaily(i)),l(n)||p(n,this.hour))break}},e.prototype.addMinutes=function(t,e,n,r){for(e&&(this.minute+=Math.floor((1439-(60*this.hour+this.minute))/t)*t);;){this.minute+=t;var i=d(this.minute,60),o=i.div,a=i.mod;if(o&&(this.minute=a,this.addHours(o,!1,n)),(l(n)||p(n,this.hour))&&(l(r)||p(r,this.minute)))break}},e.prototype.addSeconds=function(t,e,n,r,i){for(e&&(this.second+=Math.floor((86399-(3600*this.hour+60*this.minute+this.second))/t)*t);;){this.second+=t;var o=d(this.second,60),a=o.div,s=o.mod;if(a&&(this.second=s,this.addMinutes(a,!1,n,r)),(l(n)||p(n,this.hour))&&(l(r)||p(r,this.minute))&&(l(i)||p(i,this.second)))break}},e.prototype.fixDay=function(){if(!(this.day<=28)){var t=U(this.year,this.month-1)[1];if(!(this.day<=t))for(;this.day>t;){if(this.day-=t,++this.month,13===this.month&&(this.month=1,++this.year,this.year>9999))return;t=U(this.year,this.month-1)[1]}}},e.prototype.add=function(t,e){var n=t.freq,r=t.interval,i=t.wkst,o=t.byhour,a=t.byminute,s=t.bysecond;switch(n){case Z.YEARLY:return this.addYears(r);case Z.MONTHLY:return this.addMonths(r);case Z.WEEKLY:return this.addWeekly(r,i);case Z.DAILY:return this.addDaily(r);case Z.HOURLY:return this.addHours(r,e,o);case Z.MINUTELY:return this.addMinutes(r,e,o,a);case Z.SECONDLY:return this.addSeconds(r,e,o,a,s)}},e}(tt);function nt(t){for(var e=[],n=0,r=Object.keys(t);n=-366&&y<=366))throw new Error("bysetpos must be between 1 and 366, or between -366 and -1")}}if(!(Boolean(e.byweekno)||f(e.byweekno)||f(e.byyearday)||Boolean(e.bymonthday)||f(e.bymonthday)||i(e.byweekday)||i(e.byeaster)))switch(e.freq){case Pt.YEARLY:e.bymonth||(e.bymonth=e.dtstart.getUTCMonth()+1),e.bymonthday=e.dtstart.getUTCDate();break;case Pt.MONTHLY:e.bymonthday=e.dtstart.getUTCDate();break;case Pt.WEEKLY:e.byweekday=[S(e.dtstart)]}if(i(e.bymonth)&&!s(e.bymonth)&&(e.bymonth=[e.bymonth]),i(e.byyearday)&&!s(e.byyearday)&&o(e.byyearday)&&(e.byyearday=[e.byyearday]),i(e.bymonthday))if(s(e.bymonthday)){var u=[],h=[];for(n=0;n0?u.push(y):y<0&&h.push(y)}e.bymonthday=u,e.bynmonthday=h}else e.bymonthday<0?(e.bynmonthday=[e.bymonthday],e.bymonthday=[]):(e.bynmonthday=[],e.bymonthday=[e.bymonthday]);else e.bymonthday=[],e.bynmonthday=[];if(i(e.byweekno)&&!s(e.byweekno)&&(e.byweekno=[e.byweekno]),i(e.byweekday))if(o(e.byweekday))e.byweekday=[e.byweekday],e.bynweekday=null;else if(a(e.byweekday))e.byweekday=[r.fromStr(e.byweekday).weekday],e.bynweekday=null;else if(e.byweekday instanceof r)!e.byweekday.n||e.freq>Pt.MONTHLY?(e.byweekday=[e.byweekday.weekday],e.bynweekday=null):(e.bynweekday=[[e.byweekday.weekday,e.byweekday.n]],e.byweekday=null);else{var c=[],d=[];for(n=0;nPt.MONTHLY?c.push(l.weekday):d.push([l.weekday,l.n])}e.byweekday=f(c)?c:null,e.bynweekday=f(d)?d:null}else e.bynweekday=null;return i(e.byhour)?o(e.byhour)&&(e.byhour=[e.byhour]):e.byhour=e.freq=4?(d=0,r=y.yearlen+c(u-e.wkst,7)):r=o-d;for(var f=Math.floor(r/7),m=c(r,7),w=Math.floor(f+m/4),v=0;v0&&g<=w){var E=void 0;g>1?(E=d+7*(g-1),d!==n&&(E-=7-n)):E=d;for(var T=0;T<7&&(y.wnomask[E]=1,E++,y.wdaymask[E]!==e.wkst);T++);}}if(p(e.byweekno,1)){E=d+7*w;if(d!==n&&(E-=7-n),E=4?(U=0,L=Y+c(O-e.wkst,7)):L=o-d,D=Math.floor(52+c(L,7)/4)}if(p(e.byweekno,D))for(E=0;E=Pt.HOURLY&&f(i)&&!p(i,e.hour)||r>=Pt.MINUTELY&&f(o)&&!p(o,e.minute)||r>=Pt.SECONDLY&&f(a)&&!p(a,e.second))return[];return t.gettimeset(r)(e.hour,e.minute,e.second,e.millisecond)}(y,h,e);;){var d=y.getdayset(r)(h.year,h.month,h.day),l=d[0],b=d[1],m=d[2],w=jt(l,b,m,y,e);if(f(s))for(var v=Rt(s,c,b,m,y,l),g=0;ga)return It(t);if(k>=n){var E=Ct(k,e);if(!t.accept(E))return It(t);if(u&&!--u)return It(t)}}else for(g=b;ga)return It(t);if(k>=n){E=Ct(k,e);if(!t.accept(E))return It(t);if(u&&!--u)return It(t)}}}if(0===e.interval)return It(t);if(h.add(e,w),h.year>9999)return It(t);Q(r)||(c=y.gettimeset(r)(h.hour,h.minute,h.second,0)),y.rebuild(h.year,h.month)}}function At(t,e,n){var r=n.bymonth,i=n.byweekno,o=n.byweekday,a=n.byeaster,s=n.bymonthday,u=n.bynmonthday,h=n.byyearday;return f(r)&&!p(r,t.mmask[e])||f(i)&&!t.wnomask[e]||f(o)&&!p(o,t.wdaymask[e])||f(t.nwdaymask)&&!t.nwdaymask[e]||null!==a&&!p(t.eastermask,e)||(f(s)||f(u))&&!p(s,t.mdaymask[e])&&!p(u,t.nmdaymask[e])||f(h)&&(e=t.yearlen&&!p(h,e+1-t.yearlen)&&!p(h,-t.nextyearlen+e-t.yearlen))}function Ct(t,e){return new ht(t,e.tzid).rezonedDate()}function It(t){return t.getValue()}function jt(t,e,n,r,i){for(var o=!1,a=e;a0&&" "===i[0]?(n[r-1]+=i.slice(1),n.splice(r,1)):r+=1:n.splice(r,1)}return n}(t,e.unfold);return h.forEach((function(t){var e;if(t){var a=function(t){var e=function(t){if(-1===t.indexOf(":"))return{name:"RRULE",value:t};var e=(i=t,o=":",a=1,s=i.split(o),a?s.slice(0,a).concat([s.slice(a).join(o)]):s),n=e[0],r=e[1];var i,o,a,s;return{name:n,value:r}}(t),n=e.name,r=e.value,i=n.split(";");if(!i)throw new Error("empty property name");return{name:i[0].toUpperCase(),parms:i.slice(1),value:r}}(t),s=a.name,h=a.parms,y=a.value;switch(s.toUpperCase()){case"RRULE":if(h.length)throw new Error("unsupported RRULE parm: ".concat(h.join(",")));n.push(it(t));break;case"RDATE":var c=(null!==(e=/RDATE(?:;TZID=([^:=]+))?/i.exec(t))&&void 0!==e?e:[])[1];c&&!u&&(u=c),r=r.concat(Zt(y,h));break;case"EXRULE":if(h.length)throw new Error("unsupported EXRULE parm: ".concat(h.join(",")));i.push(it(y));break;case"EXDATE":o=o.concat(Zt(y,h));break;case"DTSTART":break;default:throw new Error("unsupported property: "+s)}}})),{dtstart:s,tzid:u,rrulevals:n,rdatevals:r,exrulevals:i,exdatevals:o}}function Kt(t,e){return void 0===e&&(e={}),function(t,e){var n=zt(t,e),r=n.rrulevals,i=n.rdatevals,o=n.exrulevals,a=n.exdatevals,s=n.dtstart,u=n.tzid,h=!1===e.cache;if(e.compatible&&(e.forceset=!0,e.unfold=!0),e.forceset||r.length>1||i.length||o.length||a.length){var y=new Gt(h);return y.dtstart(s),y.tzid(u||void 0),r.forEach((function(t){y.rrule(new Pt(Bt(t,s,u),h))})),i.forEach((function(t){y.rdate(t)})),o.forEach((function(t){y.exrule(new Pt(Bt(t,s,u),h))})),a.forEach((function(t){y.exdate(t)})),e.compatible&&e.dtstart&&y.rdate(s),y}var c=r[0]||{};return new Pt(Bt(c,c.dtstart||e.dtstart||s,c.tzid||e.tzid||u),h)}(t,function(t){var e=[],n=Object.keys(t),r=Object.keys(Ft);if(n.forEach((function(t){p(r,t)||e.push(t)})),e.length)throw new Error("Invalid options: "+e.join(", "));return W(W({},Ft),t)}(e))}function Bt(t,e,n){return W(W({},t),{dtstart:e,tzid:n})}function Zt(t,e){return function(t){t.forEach((function(t){if(!/(VALUE=DATE(-TIME)?)|(TZID=)/.test(t))throw new Error("unsupported RDATE/EXDATE parm: "+t)}))}(e),t.split(",").map((function(t){return N(t)}))}function Xt(t){var e=this;return function(n){if(void 0!==n&&(e["_".concat(t)]=n),void 0!==e["_".concat(t)])return e["_".concat(t)];for(var r=0;r {\nreturn ","// The require scope\nvar __webpack_require__ = {};\n\n","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","// =============================================================================\n// Weekday\n// =============================================================================\n\nexport type WeekdayStr = 'MO' | 'TU' | 'WE' | 'TH' | 'FR' | 'SA' | 'SU'\nexport const ALL_WEEKDAYS: WeekdayStr[] = [\n 'MO',\n 'TU',\n 'WE',\n 'TH',\n 'FR',\n 'SA',\n 'SU',\n]\n\nexport class Weekday {\n public readonly weekday: number\n public readonly n?: number\n\n constructor(weekday: number, n?: number) {\n if (n === 0) throw new Error(\"Can't create weekday with n == 0\")\n this.weekday = weekday\n this.n = n\n }\n\n static fromStr(str: WeekdayStr): Weekday {\n return new Weekday(ALL_WEEKDAYS.indexOf(str))\n }\n\n // __call__ - Cannot call the object directly, do it through\n // e.g. RRule.TH.nth(-1) instead,\n nth(n: number) {\n return this.n === n ? this : new Weekday(this.weekday, n)\n }\n\n // __eq__\n equals(other: Weekday) {\n return this.weekday === other.weekday && this.n === other.n\n }\n\n // __repr__\n toString() {\n let s: string = ALL_WEEKDAYS[this.weekday]\n if (this.n) s = (this.n > 0 ? '+' : '') + String(this.n) + s\n return s\n }\n\n getJsWeekday() {\n return this.weekday === 6 ? 0 : this.weekday + 1\n }\n}\n","// =============================================================================\n// Helper functions\n// =============================================================================\n\nimport { ALL_WEEKDAYS, WeekdayStr } from './weekday'\n\nexport const isPresent = function (\n value?: T | null | undefined\n): value is T {\n return value !== null && value !== undefined\n}\n\nexport const isNumber = function (value: unknown): value is number {\n return typeof value === 'number'\n}\n\nexport const isWeekdayStr = function (value: unknown): value is WeekdayStr {\n return typeof value === 'string' && ALL_WEEKDAYS.includes(value as WeekdayStr)\n}\n\nexport const isArray = Array.isArray\n\n/**\n * Simplified version of python's range()\n */\nexport const range = function (start: number, end: number = start): number[] {\n if (arguments.length === 1) {\n end = start\n start = 0\n }\n const rang = []\n for (let i = start; i < end; i++) rang.push(i)\n return rang\n}\n\nexport const clone = function (array: T[]): T[] {\n return ([] as T[]).concat(array)\n}\n\nexport const repeat = function (value: T | T[], times: number): (T | T[])[] {\n let i = 0\n const array: (T | T[])[] = []\n\n if (isArray(value)) {\n for (; i < times; i++) array[i] = ([] as T[]).concat(value)\n } else {\n for (; i < times; i++) array[i] = value\n }\n return array\n}\n\nexport const toArray = function (item: T | T[]): T[] {\n if (isArray(item)) {\n return item\n }\n\n return [item]\n}\n\nexport function padStart(\n item: string | number,\n targetLength: number,\n padString = ' '\n) {\n const str = String(item)\n targetLength = targetLength >> 0\n if (str.length > targetLength) {\n return String(str)\n }\n\n targetLength = targetLength - str.length\n if (targetLength > padString.length) {\n padString += repeat(padString, targetLength / padString.length)\n }\n\n return padString.slice(0, targetLength) + String(str)\n}\n\n/**\n * Python like split\n */\nexport const split = function (str: string, sep: string, num: number) {\n const splits = str.split(sep)\n return num\n ? splits.slice(0, num).concat([splits.slice(num).join(sep)])\n : splits\n}\n\n/**\n * closure/goog/math/math.js:modulo\n * Copyright 2006 The Closure Library Authors.\n * The % operator in JavaScript returns the remainder of a / b, but differs from\n * some other languages in that the result will have the same sign as the\n * dividend. For example, -1 % 8 == -1, whereas in some other languages\n * (such as Python) the result would be 7. This function emulates the more\n * correct modulo behavior, which is useful for certain applications such as\n * calculating an offset index in a circular list.\n *\n * @param {number} a The dividend.\n * @param {number} b The divisor.\n * @return {number} a % b where the result is between 0 and b (either 0 <= x < b\n * or b < x <= 0, depending on the sign of b).\n */\nexport const pymod = function (a: number, b: number) {\n const r = a % b\n // If r and b differ in sign, add b to wrap the result to the correct sign.\n return r * b < 0 ? r + b : r\n}\n\n/**\n * @see: \n */\nexport const divmod = function (a: number, b: number) {\n return { div: Math.floor(a / b), mod: pymod(a, b) }\n}\n\nexport const empty = function (obj: T[] | null | undefined) {\n return !isPresent(obj) || obj.length === 0\n}\n\n/**\n * Python-like boolean\n *\n * @return {Boolean} value of an object/primitive, taking into account\n * the fact that in Python an empty list's/tuple's\n * boolean value is False, whereas in JS it's true\n */\nexport const notEmpty = function (obj: T[] | null | undefined): obj is T[] {\n return !empty(obj)\n}\n\n/**\n * Return true if a value is in an array\n */\nexport const includes = function (arr: T[] | null | undefined, val: T) {\n return notEmpty(arr) && arr.indexOf(val) !== -1\n}\n","import { padStart } from './helpers'\nimport { Time } from './datetime'\n\ntype Datelike = Pick\n\nexport const datetime = function (\n y: number,\n m: number,\n d: number,\n h = 0,\n i = 0,\n s = 0\n) {\n return new Date(Date.UTC(y, m - 1, d, h, i, s))\n}\n\n/**\n * General date-related utilities.\n * Also handles several incompatibilities between JavaScript and Python\n *\n */\nexport const MONTH_DAYS = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]\n\n/**\n * Number of milliseconds of one day\n */\nexport const ONE_DAY = 1000 * 60 * 60 * 24\n\n/**\n * @see: \n */\nexport const MAXYEAR = 9999\n\n/**\n * Python uses 1-Jan-1 as the base for calculating ordinals but we don't\n * want to confuse the JS engine with milliseconds > Number.MAX_NUMBER,\n * therefore we use 1-Jan-1970 instead\n */\nexport const ORDINAL_BASE = datetime(1970, 1, 1)\n\n/**\n * Python: MO-SU: 0 - 6\n * JS: SU-SAT 0 - 6\n */\nexport const PY_WEEKDAYS = [6, 0, 1, 2, 3, 4, 5]\n\n/**\n * py_date.timetuple()[7]\n */\nexport const getYearDay = function (date: Date) {\n const dateNoTime = new Date(\n date.getUTCFullYear(),\n date.getUTCMonth(),\n date.getUTCDate()\n )\n return (\n Math.ceil(\n (dateNoTime.valueOf() - new Date(date.getUTCFullYear(), 0, 1).valueOf()) /\n ONE_DAY\n ) + 1\n )\n}\n\nexport const isLeapYear = function (year: number) {\n return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0\n}\n\nexport const isDate = function (value: unknown): value is Date {\n return value instanceof Date\n}\n\nexport const isValidDate = function (value: unknown): value is Date {\n return isDate(value) && !isNaN(value.getTime())\n}\n\n/**\n * @return {Number} the date's timezone offset in ms\n */\nexport const tzOffset = function (date: Date) {\n return date.getTimezoneOffset() * 60 * 1000\n}\n\n/**\n * @see: \n */\nexport const daysBetween = function (date1: Date, date2: Date) {\n // The number of milliseconds in one day\n // Convert both dates to milliseconds\n const date1ms = date1.getTime()\n const date2ms = date2.getTime()\n\n // Calculate the difference in milliseconds\n const differencems = date1ms - date2ms\n\n // Convert back to days and return\n return Math.round(differencems / ONE_DAY)\n}\n\n/**\n * @see: \n */\nexport const toOrdinal = function (date: Date) {\n return daysBetween(date, ORDINAL_BASE)\n}\n\n/**\n * @see - \n */\nexport const fromOrdinal = function (ordinal: number) {\n return new Date(ORDINAL_BASE.getTime() + ordinal * ONE_DAY)\n}\n\nexport const getMonthDays = function (date: Date) {\n const month = date.getUTCMonth()\n return month === 1 && isLeapYear(date.getUTCFullYear())\n ? 29\n : MONTH_DAYS[month]\n}\n\n/**\n * @return {Number} python-like weekday\n */\nexport const getWeekday = function (date: Date) {\n return PY_WEEKDAYS[date.getUTCDay()]\n}\n\n/**\n * @see: \n */\nexport const monthRange = function (year: number, month: number) {\n const date = datetime(year, month + 1, 1)\n return [getWeekday(date), getMonthDays(date)]\n}\n\n/**\n * @see: \n */\nexport const combine = function (date: Date, time: Date | Time) {\n time = time || date\n return new Date(\n Date.UTC(\n date.getUTCFullYear(),\n date.getUTCMonth(),\n date.getUTCDate(),\n time.getHours(),\n time.getMinutes(),\n time.getSeconds(),\n time.getMilliseconds()\n )\n )\n}\n\nexport const clone = function (date: Date | Time) {\n const dolly = new Date(date.getTime())\n return dolly\n}\n\nexport const cloneDates = function (dates: Date[] | Time[]) {\n const clones = []\n for (let i = 0; i < dates.length; i++) {\n clones.push(clone(dates[i]))\n }\n return clones\n}\n\n/**\n * Sorts an array of Date or Time objects\n */\nexport const sort = function (dates: T[]) {\n dates.sort(function (a, b) {\n return a.getTime() - b.getTime()\n })\n}\n\nexport const timeToUntilString = function (time: number, utc = true) {\n const date = new Date(time)\n return [\n padStart(date.getUTCFullYear().toString(), 4, '0'),\n padStart(date.getUTCMonth() + 1, 2, '0'),\n padStart(date.getUTCDate(), 2, '0'),\n 'T',\n padStart(date.getUTCHours(), 2, '0'),\n padStart(date.getUTCMinutes(), 2, '0'),\n padStart(date.getUTCSeconds(), 2, '0'),\n utc ? 'Z' : '',\n ].join('')\n}\n\nexport const untilStringToDate = function (until: string) {\n const re = /^(\\d{4})(\\d{2})(\\d{2})(T(\\d{2})(\\d{2})(\\d{2})Z?)?$/\n const bits = re.exec(until)\n\n if (!bits) throw new Error(`Invalid UNTIL value: ${until}`)\n\n return new Date(\n Date.UTC(\n parseInt(bits[1], 10),\n parseInt(bits[2], 10) - 1,\n parseInt(bits[3], 10),\n parseInt(bits[5], 10) || 0,\n parseInt(bits[6], 10) || 0,\n parseInt(bits[7], 10) || 0\n )\n )\n}\n\nconst dateTZtoISO8601 = function (date: Date, timeZone: string) {\n // date format for sv-SE is almost ISO8601\n const dateStr = date.toLocaleString('sv-SE', { timeZone })\n // '2023-02-07 10:41:36'\n return dateStr.replace(' ', 'T') + 'Z'\n}\n\nexport const dateInTimeZone = function (date: Date, timeZone: string) {\n const localTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone\n // Date constructor can only reliably parse dates in ISO8601 format\n const dateInLocalTZ = new Date(dateTZtoISO8601(date, localTimeZone))\n const dateInTargetTZ = new Date(dateTZtoISO8601(date, timeZone ?? 'UTC'))\n const tzOffset = dateInTargetTZ.getTime() - dateInLocalTZ.getTime()\n\n return new Date(date.getTime() - tzOffset)\n}\n","import { QueryMethodTypes, IterResultType } from './types'\n\n// =============================================================================\n// Results\n// =============================================================================\n\nexport interface IterArgs {\n inc: boolean\n before: Date\n after: Date\n dt: Date\n _value: Date | Date[] | null\n}\n\n/**\n * This class helps us to emulate python's generators, sorta.\n */\nexport default class IterResult {\n public readonly method: M\n public readonly args: Partial\n public readonly minDate: Date | null = null\n public readonly maxDate: Date | null = null\n public _result: Date[] = []\n public total = 0\n\n constructor(method: M, args: Partial) {\n this.method = method\n this.args = args\n\n if (method === 'between') {\n this.maxDate = args.inc\n ? args.before\n : new Date(args.before.getTime() - 1)\n this.minDate = args.inc ? args.after : new Date(args.after.getTime() + 1)\n } else if (method === 'before') {\n this.maxDate = args.inc ? args.dt : new Date(args.dt.getTime() - 1)\n } else if (method === 'after') {\n this.minDate = args.inc ? args.dt : new Date(args.dt.getTime() + 1)\n }\n }\n\n /**\n * Possibly adds a date into the result.\n *\n * @param {Date} date - the date isn't necessarly added to the result\n * list (if it is too late/too early)\n * @return {Boolean} true if it makes sense to continue the iteration\n * false if we're done.\n */\n accept(date: Date) {\n ++this.total\n const tooEarly = this.minDate && date < this.minDate\n const tooLate = this.maxDate && date > this.maxDate\n\n if (this.method === 'between') {\n if (tooEarly) return true\n if (tooLate) return false\n } else if (this.method === 'before') {\n if (tooLate) return false\n } else if (this.method === 'after') {\n if (tooEarly) return true\n this.add(date)\n return false\n }\n\n return this.add(date)\n }\n\n /**\n *\n * @param {Date} date that is part of the result.\n * @return {Boolean} whether we are interested in more values.\n */\n add(date: Date) {\n this._result.push(date)\n return true\n }\n\n /**\n * 'before' and 'after' return only one date, whereas 'all'\n * and 'between' an array.\n *\n * @return {Date,Array?}\n */\n getValue(): IterResultType {\n const res = this._result\n switch (this.method) {\n case 'all':\n case 'between':\n return res as IterResultType\n case 'before':\n case 'after':\n default:\n return (res.length ? res[res.length - 1] : null) as IterResultType\n }\n }\n\n clone() {\n return new IterResult(this.method, this.args)\n }\n}\n","/******************************************************************************\r\nCopyright (c) Microsoft Corporation.\r\n\r\nPermission to use, copy, modify, and/or distribute this software for any\r\npurpose with or without fee is hereby granted.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\r\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\r\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\r\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\r\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r\nPERFORMANCE OF THIS SOFTWARE.\r\n***************************************************************************** */\r\n/* global Reflect, Promise */\r\n\r\nvar extendStatics = function(d, b) {\r\n extendStatics = Object.setPrototypeOf ||\r\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\r\n function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };\r\n return extendStatics(d, b);\r\n};\r\n\r\nexport function __extends(d, b) {\r\n if (typeof b !== \"function\" && b !== null)\r\n throw new TypeError(\"Class extends value \" + String(b) + \" is not a constructor or null\");\r\n extendStatics(d, b);\r\n function __() { this.constructor = d; }\r\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\r\n}\r\n\r\nexport var __assign = function() {\r\n __assign = Object.assign || function __assign(t) {\r\n for (var s, i = 1, n = arguments.length; i < n; i++) {\r\n s = arguments[i];\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\r\n }\r\n return t;\r\n }\r\n return __assign.apply(this, arguments);\r\n}\r\n\r\nexport function __rest(s, e) {\r\n var t = {};\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)\r\n t[p] = s[p];\r\n if (s != null && typeof Object.getOwnPropertySymbols === \"function\")\r\n for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\r\n if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))\r\n t[p[i]] = s[p[i]];\r\n }\r\n return t;\r\n}\r\n\r\nexport function __decorate(decorators, target, key, desc) {\r\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\r\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\r\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\r\n return c > 3 && r && Object.defineProperty(target, key, r), r;\r\n}\r\n\r\nexport function __param(paramIndex, decorator) {\r\n return function (target, key) { decorator(target, key, paramIndex); }\r\n}\r\n\r\nexport function __metadata(metadataKey, metadataValue) {\r\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(metadataKey, metadataValue);\r\n}\r\n\r\nexport function __awaiter(thisArg, _arguments, P, generator) {\r\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\r\n return new (P || (P = Promise))(function (resolve, reject) {\r\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\r\n step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n });\r\n}\r\n\r\nexport function __generator(thisArg, body) {\r\n var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;\r\n return g = { next: verb(0), \"throw\": verb(1), \"return\": verb(2) }, typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\r\n function verb(n) { return function (v) { return step([n, v]); }; }\r\n function step(op) {\r\n if (f) throw new TypeError(\"Generator is already executing.\");\r\n while (_) try {\r\n if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\r\n if (y = 0, t) op = [op[0] & 2, t.value];\r\n switch (op[0]) {\r\n case 0: case 1: t = op; break;\r\n case 4: _.label++; return { value: op[1], done: false };\r\n case 5: _.label++; y = op[1]; op = [0]; continue;\r\n case 7: op = _.ops.pop(); _.trys.pop(); continue;\r\n default:\r\n if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\r\n if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\r\n if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\r\n if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\r\n if (t[2]) _.ops.pop();\r\n _.trys.pop(); continue;\r\n }\r\n op = body.call(thisArg, _);\r\n } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\r\n if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\r\n }\r\n}\r\n\r\nexport var __createBinding = Object.create ? (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n var desc = Object.getOwnPropertyDescriptor(m, k);\r\n if (!desc || (\"get\" in desc ? !m.__esModule : desc.writable || desc.configurable)) {\r\n desc = { enumerable: true, get: function() { return m[k]; } };\r\n }\r\n Object.defineProperty(o, k2, desc);\r\n}) : (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n o[k2] = m[k];\r\n});\r\n\r\nexport function __exportStar(m, o) {\r\n for (var p in m) if (p !== \"default\" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p);\r\n}\r\n\r\nexport function __values(o) {\r\n var s = typeof Symbol === \"function\" && Symbol.iterator, m = s && o[s], i = 0;\r\n if (m) return m.call(o);\r\n if (o && typeof o.length === \"number\") return {\r\n next: function () {\r\n if (o && i >= o.length) o = void 0;\r\n return { value: o && o[i++], done: !o };\r\n }\r\n };\r\n throw new TypeError(s ? \"Object is not iterable.\" : \"Symbol.iterator is not defined.\");\r\n}\r\n\r\nexport function __read(o, n) {\r\n var m = typeof Symbol === \"function\" && o[Symbol.iterator];\r\n if (!m) return o;\r\n var i = m.call(o), r, ar = [], e;\r\n try {\r\n while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);\r\n }\r\n catch (error) { e = { error: error }; }\r\n finally {\r\n try {\r\n if (r && !r.done && (m = i[\"return\"])) m.call(i);\r\n }\r\n finally { if (e) throw e.error; }\r\n }\r\n return ar;\r\n}\r\n\r\n/** @deprecated */\r\nexport function __spread() {\r\n for (var ar = [], i = 0; i < arguments.length; i++)\r\n ar = ar.concat(__read(arguments[i]));\r\n return ar;\r\n}\r\n\r\n/** @deprecated */\r\nexport function __spreadArrays() {\r\n for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;\r\n for (var r = Array(s), k = 0, i = 0; i < il; i++)\r\n for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)\r\n r[k] = a[j];\r\n return r;\r\n}\r\n\r\nexport function __spreadArray(to, from, pack) {\r\n if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {\r\n if (ar || !(i in from)) {\r\n if (!ar) ar = Array.prototype.slice.call(from, 0, i);\r\n ar[i] = from[i];\r\n }\r\n }\r\n return to.concat(ar || Array.prototype.slice.call(from));\r\n}\r\n\r\nexport function __await(v) {\r\n return this instanceof __await ? (this.v = v, this) : new __await(v);\r\n}\r\n\r\nexport function __asyncGenerator(thisArg, _arguments, generator) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var g = generator.apply(thisArg, _arguments || []), i, q = [];\r\n return i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i;\r\n function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }\r\n function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }\r\n function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }\r\n function fulfill(value) { resume(\"next\", value); }\r\n function reject(value) { resume(\"throw\", value); }\r\n function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }\r\n}\r\n\r\nexport function __asyncDelegator(o) {\r\n var i, p;\r\n return i = {}, verb(\"next\"), verb(\"throw\", function (e) { throw e; }), verb(\"return\"), i[Symbol.iterator] = function () { return this; }, i;\r\n function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === \"return\" } : f ? f(v) : v; } : f; }\r\n}\r\n\r\nexport function __asyncValues(o) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var m = o[Symbol.asyncIterator], i;\r\n return m ? m.call(o) : (o = typeof __values === \"function\" ? __values(o) : o[Symbol.iterator](), i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i);\r\n function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }\r\n function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }\r\n}\r\n\r\nexport function __makeTemplateObject(cooked, raw) {\r\n if (Object.defineProperty) { Object.defineProperty(cooked, \"raw\", { value: raw }); } else { cooked.raw = raw; }\r\n return cooked;\r\n};\r\n\r\nvar __setModuleDefault = Object.create ? (function(o, v) {\r\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\r\n}) : function(o, v) {\r\n o[\"default\"] = v;\r\n};\r\n\r\nexport function __importStar(mod) {\r\n if (mod && mod.__esModule) return mod;\r\n var result = {};\r\n if (mod != null) for (var k in mod) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);\r\n __setModuleDefault(result, mod);\r\n return result;\r\n}\r\n\r\nexport function __importDefault(mod) {\r\n return (mod && mod.__esModule) ? mod : { default: mod };\r\n}\r\n\r\nexport function __classPrivateFieldGet(receiver, state, kind, f) {\r\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\r\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\r\n return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\r\n}\r\n\r\nexport function __classPrivateFieldSet(receiver, state, value, kind, f) {\r\n if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\r\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\r\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\r\n return (kind === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;\r\n}\r\n\r\nexport function __classPrivateFieldIn(state, receiver) {\r\n if (receiver === null || (typeof receiver !== \"object\" && typeof receiver !== \"function\")) throw new TypeError(\"Cannot use 'in' operator on non-object\");\r\n return typeof state === \"function\" ? receiver === state : state.has(receiver);\r\n}\r\n","import IterResult, { IterArgs } from './iterresult'\n\ntype Iterator = (d: Date, len: number) => boolean\n\n/**\n * IterResult subclass that calls a callback function on each add,\n * and stops iterating when the callback returns false.\n */\nexport default class CallbackIterResult extends IterResult<'all' | 'between'> {\n private iterator: Iterator\n\n constructor(\n method: 'all' | 'between',\n args: Partial,\n iterator: Iterator\n ) {\n super(method, args)\n\n this.iterator = iterator\n }\n\n add(date: Date) {\n if (this.iterator(date, this._result.length)) {\n this._result.push(date)\n return true\n }\n return false\n }\n}\n","// =============================================================================\n// i18n\n// =============================================================================\n\nexport interface Language {\n dayNames: string[]\n monthNames: string[]\n tokens: {\n [k: string]: RegExp\n }\n}\n\nconst ENGLISH: Language = {\n dayNames: [\n 'Sunday',\n 'Monday',\n 'Tuesday',\n 'Wednesday',\n 'Thursday',\n 'Friday',\n 'Saturday',\n ],\n monthNames: [\n 'January',\n 'February',\n 'March',\n 'April',\n 'May',\n 'June',\n 'July',\n 'August',\n 'September',\n 'October',\n 'November',\n 'December',\n ],\n tokens: {\n SKIP: /^[ \\r\\n\\t]+|^\\.$/,\n number: /^[1-9][0-9]*/,\n numberAsText: /^(one|two|three)/i,\n every: /^every/i,\n 'day(s)': /^days?/i,\n 'weekday(s)': /^weekdays?/i,\n 'week(s)': /^weeks?/i,\n 'hour(s)': /^hours?/i,\n 'minute(s)': /^minutes?/i,\n 'month(s)': /^months?/i,\n 'year(s)': /^years?/i,\n on: /^(on|in)/i,\n at: /^(at)/i,\n the: /^the/i,\n first: /^first/i,\n second: /^second/i,\n third: /^third/i,\n nth: /^([1-9][0-9]*)(\\.|th|nd|rd|st)/i,\n last: /^last/i,\n for: /^for/i,\n 'time(s)': /^times?/i,\n until: /^(un)?til/i,\n monday: /^mo(n(day)?)?/i,\n tuesday: /^tu(e(s(day)?)?)?/i,\n wednesday: /^we(d(n(esday)?)?)?/i,\n thursday: /^th(u(r(sday)?)?)?/i,\n friday: /^fr(i(day)?)?/i,\n saturday: /^sa(t(urday)?)?/i,\n sunday: /^su(n(day)?)?/i,\n january: /^jan(uary)?/i,\n february: /^feb(ruary)?/i,\n march: /^mar(ch)?/i,\n april: /^apr(il)?/i,\n may: /^may/i,\n june: /^june?/i,\n july: /^july?/i,\n august: /^aug(ust)?/i,\n september: /^sep(t(ember)?)?/i,\n october: /^oct(ober)?/i,\n november: /^nov(ember)?/i,\n december: /^dec(ember)?/i,\n comma: /^(,\\s*|(and|or)\\s*)+/i,\n },\n}\n\nexport default ENGLISH\n","import ENGLISH, { Language } from './i18n'\nimport { RRule } from '../rrule'\nimport { Options, ByWeekday } from '../types'\nimport { Weekday } from '../weekday'\nimport { isArray, isNumber, isPresent } from '../helpers'\n\n// =============================================================================\n// Helper functions\n// =============================================================================\n\n/**\n * Return true if a value is in an array\n */\nconst contains = function (arr: string[], val: string) {\n return arr.indexOf(val) !== -1\n}\n\n// =============================================================================\n// ToText\n// =============================================================================\n\nexport type GetText = (id: string | number | Weekday) => string\n\nconst defaultGetText: GetText = (id) => id.toString()\n\nexport type DateFormatter = (year: number, month: string, day: number) => string\n\nconst defaultDateFormatter: DateFormatter = (\n year: number,\n month: string,\n day: number\n) => `${month} ${day}, ${year}`\n\n/**\n *\n * @param {RRule} rrule\n * Optional:\n * @param {Function} gettext function\n * @param {Object} language definition\n * @constructor\n */\nexport default class ToText {\n static IMPLEMENTED: string[][]\n private rrule: RRule\n private text: string[]\n private gettext: GetText\n private dateFormatter: DateFormatter\n private language: Language\n private options: Partial\n private origOptions: Partial\n private bymonthday: Options['bymonthday'] | null\n private byweekday: {\n allWeeks: ByWeekday[] | null\n someWeeks: ByWeekday[] | null\n isWeekdays: boolean\n isEveryDay: boolean\n } | null\n\n constructor(\n rrule: RRule,\n gettext: GetText = defaultGetText,\n language: Language = ENGLISH,\n dateFormatter: DateFormatter = defaultDateFormatter\n ) {\n this.text = []\n this.language = language || ENGLISH\n this.gettext = gettext\n this.dateFormatter = dateFormatter\n this.rrule = rrule\n this.options = rrule.options\n this.origOptions = rrule.origOptions\n\n if (this.origOptions.bymonthday) {\n const bymonthday = ([] as number[]).concat(this.options.bymonthday)\n const bynmonthday = ([] as number[]).concat(this.options.bynmonthday)\n\n bymonthday.sort((a, b) => a - b)\n bynmonthday.sort((a, b) => b - a)\n // 1, 2, 3, .., -5, -4, -3, ..\n this.bymonthday = bymonthday.concat(bynmonthday)\n if (!this.bymonthday.length) this.bymonthday = null\n }\n\n if (isPresent(this.origOptions.byweekday)) {\n const byweekday = !isArray(this.origOptions.byweekday)\n ? [this.origOptions.byweekday]\n : this.origOptions.byweekday\n const days = String(byweekday)\n\n this.byweekday = {\n allWeeks: byweekday.filter(function (weekday: Weekday) {\n return !weekday.n\n }),\n someWeeks: byweekday.filter(function (weekday: Weekday) {\n return Boolean(weekday.n)\n }),\n isWeekdays:\n days.indexOf('MO') !== -1 &&\n days.indexOf('TU') !== -1 &&\n days.indexOf('WE') !== -1 &&\n days.indexOf('TH') !== -1 &&\n days.indexOf('FR') !== -1 &&\n days.indexOf('SA') === -1 &&\n days.indexOf('SU') === -1,\n isEveryDay:\n days.indexOf('MO') !== -1 &&\n days.indexOf('TU') !== -1 &&\n days.indexOf('WE') !== -1 &&\n days.indexOf('TH') !== -1 &&\n days.indexOf('FR') !== -1 &&\n days.indexOf('SA') !== -1 &&\n days.indexOf('SU') !== -1,\n }\n\n const sortWeekDays = function (a: Weekday, b: Weekday) {\n return a.weekday - b.weekday\n }\n\n this.byweekday.allWeeks.sort(sortWeekDays)\n this.byweekday.someWeeks.sort(sortWeekDays)\n\n if (!this.byweekday.allWeeks.length) this.byweekday.allWeeks = null\n if (!this.byweekday.someWeeks.length) this.byweekday.someWeeks = null\n } else {\n this.byweekday = null\n }\n }\n\n /**\n * Test whether the rrule can be fully converted to text.\n *\n * @param {RRule} rrule\n * @return {Boolean}\n */\n static isFullyConvertible(rrule: RRule) {\n const canConvert = true\n\n if (!(rrule.options.freq in ToText.IMPLEMENTED)) return false\n if (rrule.origOptions.until && rrule.origOptions.count) return false\n\n for (const key in rrule.origOptions) {\n if (contains(['dtstart', 'tzid', 'wkst', 'freq'], key)) return true\n if (!contains(ToText.IMPLEMENTED[rrule.options.freq], key)) return false\n }\n\n return canConvert\n }\n\n isFullyConvertible() {\n return ToText.isFullyConvertible(this.rrule)\n }\n\n /**\n * Perform the conversion. Only some of the frequencies are supported.\n * If some of the rrule's options aren't supported, they'll\n * be omitted from the output an \"(~ approximate)\" will be appended.\n *\n * @return {*}\n */\n toString() {\n const gettext = this.gettext\n\n if (!(this.options.freq in ToText.IMPLEMENTED)) {\n return gettext('RRule error: Unable to fully convert this rrule to text')\n }\n\n this.text = [gettext('every')]\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n this[RRule.FREQUENCIES[this.options.freq]]()\n\n if (this.options.until) {\n this.add(gettext('until'))\n const until = this.options.until\n this.add(\n this.dateFormatter(\n until.getUTCFullYear(),\n this.language.monthNames[until.getUTCMonth()],\n until.getUTCDate()\n )\n )\n } else if (this.options.count) {\n this.add(gettext('for'))\n .add(this.options.count.toString())\n .add(\n this.plural(this.options.count) ? gettext('times') : gettext('time')\n )\n }\n\n if (!this.isFullyConvertible()) this.add(gettext('(~ approximate)'))\n\n return this.text.join('')\n }\n\n HOURLY() {\n const gettext = this.gettext\n\n if (this.options.interval !== 1) this.add(this.options.interval.toString())\n\n this.add(\n this.plural(this.options.interval) ? gettext('hours') : gettext('hour')\n )\n }\n\n MINUTELY() {\n const gettext = this.gettext\n\n if (this.options.interval !== 1) this.add(this.options.interval.toString())\n\n this.add(\n this.plural(this.options.interval)\n ? gettext('minutes')\n : gettext('minute')\n )\n }\n\n DAILY() {\n const gettext = this.gettext\n\n if (this.options.interval !== 1) this.add(this.options.interval.toString())\n\n if (this.byweekday && this.byweekday.isWeekdays) {\n this.add(\n this.plural(this.options.interval)\n ? gettext('weekdays')\n : gettext('weekday')\n )\n } else {\n this.add(\n this.plural(this.options.interval) ? gettext('days') : gettext('day')\n )\n }\n\n if (this.origOptions.bymonth) {\n this.add(gettext('in'))\n this._bymonth()\n }\n\n if (this.bymonthday) {\n this._bymonthday()\n } else if (this.byweekday) {\n this._byweekday()\n } else if (this.origOptions.byhour) {\n this._byhour()\n }\n }\n\n WEEKLY() {\n const gettext = this.gettext\n\n if (this.options.interval !== 1) {\n this.add(this.options.interval.toString()).add(\n this.plural(this.options.interval) ? gettext('weeks') : gettext('week')\n )\n }\n\n if (this.byweekday && this.byweekday.isWeekdays) {\n if (this.options.interval === 1) {\n this.add(\n this.plural(this.options.interval)\n ? gettext('weekdays')\n : gettext('weekday')\n )\n } else {\n this.add(gettext('on')).add(gettext('weekdays'))\n }\n } else if (this.byweekday && this.byweekday.isEveryDay) {\n this.add(\n this.plural(this.options.interval) ? gettext('days') : gettext('day')\n )\n } else {\n if (this.options.interval === 1) this.add(gettext('week'))\n\n if (this.origOptions.bymonth) {\n this.add(gettext('in'))\n this._bymonth()\n }\n\n if (this.bymonthday) {\n this._bymonthday()\n } else if (this.byweekday) {\n this._byweekday()\n }\n\n if (this.origOptions.byhour) {\n this._byhour()\n }\n }\n }\n\n MONTHLY() {\n const gettext = this.gettext\n\n if (this.origOptions.bymonth) {\n if (this.options.interval !== 1) {\n this.add(this.options.interval.toString()).add(gettext('months'))\n if (this.plural(this.options.interval)) this.add(gettext('in'))\n } else {\n // this.add(gettext('MONTH'))\n }\n this._bymonth()\n } else {\n if (this.options.interval !== 1) {\n this.add(this.options.interval.toString())\n }\n this.add(\n this.plural(this.options.interval)\n ? gettext('months')\n : gettext('month')\n )\n }\n if (this.bymonthday) {\n this._bymonthday()\n } else if (this.byweekday && this.byweekday.isWeekdays) {\n this.add(gettext('on')).add(gettext('weekdays'))\n } else if (this.byweekday) {\n this._byweekday()\n }\n }\n\n YEARLY() {\n const gettext = this.gettext\n\n if (this.origOptions.bymonth) {\n if (this.options.interval !== 1) {\n this.add(this.options.interval.toString())\n this.add(gettext('years'))\n } else {\n // this.add(gettext('YEAR'))\n }\n this._bymonth()\n } else {\n if (this.options.interval !== 1) {\n this.add(this.options.interval.toString())\n }\n this.add(\n this.plural(this.options.interval) ? gettext('years') : gettext('year')\n )\n }\n\n if (this.bymonthday) {\n this._bymonthday()\n } else if (this.byweekday) {\n this._byweekday()\n }\n\n if (this.options.byyearday) {\n this.add(gettext('on the'))\n .add(this.list(this.options.byyearday, this.nth, gettext('and')))\n .add(gettext('day'))\n }\n\n if (this.options.byweekno) {\n this.add(gettext('in'))\n .add(\n this.plural((this.options.byweekno as number[]).length)\n ? gettext('weeks')\n : gettext('week')\n )\n .add(this.list(this.options.byweekno, undefined, gettext('and')))\n }\n }\n\n private _bymonthday() {\n const gettext = this.gettext\n if (this.byweekday && this.byweekday.allWeeks) {\n this.add(gettext('on'))\n .add(\n this.list(this.byweekday.allWeeks, this.weekdaytext, gettext('or'))\n )\n .add(gettext('the'))\n .add(this.list(this.bymonthday, this.nth, gettext('or')))\n } else {\n this.add(gettext('on the')).add(\n this.list(this.bymonthday, this.nth, gettext('and'))\n )\n }\n // this.add(gettext('DAY'))\n }\n\n private _byweekday() {\n const gettext = this.gettext\n if (this.byweekday.allWeeks && !this.byweekday.isWeekdays) {\n this.add(gettext('on')).add(\n this.list(this.byweekday.allWeeks, this.weekdaytext)\n )\n }\n\n if (this.byweekday.someWeeks) {\n if (this.byweekday.allWeeks) this.add(gettext('and'))\n\n this.add(gettext('on the')).add(\n this.list(this.byweekday.someWeeks, this.weekdaytext, gettext('and'))\n )\n }\n }\n\n private _byhour() {\n const gettext = this.gettext\n\n this.add(gettext('at')).add(\n this.list(this.origOptions.byhour, undefined, gettext('and'))\n )\n }\n\n private _bymonth() {\n this.add(\n this.list(this.options.bymonth, this.monthtext, this.gettext('and'))\n )\n }\n\n nth(n: number | string) {\n n = parseInt(n.toString(), 10)\n let nth: string\n const gettext = this.gettext\n\n if (n === -1) return gettext('last')\n\n const npos = Math.abs(n)\n switch (npos) {\n case 1:\n case 21:\n case 31:\n nth = npos + gettext('st')\n break\n case 2:\n case 22:\n nth = npos + gettext('nd')\n break\n case 3:\n case 23:\n nth = npos + gettext('rd')\n break\n default:\n nth = npos + gettext('th')\n }\n\n return n < 0 ? nth + ' ' + gettext('last') : nth\n }\n\n monthtext(m: number) {\n return this.language.monthNames[m - 1]\n }\n\n weekdaytext(wday: Weekday | number) {\n const weekday = isNumber(wday) ? (wday + 1) % 7 : wday.getJsWeekday()\n return (\n ((wday as Weekday).n ? this.nth((wday as Weekday).n) + ' ' : '') +\n this.language.dayNames[weekday]\n )\n }\n\n plural(n: number) {\n return n % 100 !== 1\n }\n\n add(s: string) {\n this.text.push(' ')\n this.text.push(s)\n return this\n }\n\n list(\n arr: ByWeekday | ByWeekday[],\n callback?: GetText,\n finalDelim?: string,\n delim = ','\n ) {\n if (!isArray(arr)) {\n arr = [arr]\n }\n const delimJoin = function (\n array: string[],\n delimiter: string,\n finalDelimiter: string\n ) {\n let list = ''\n\n for (let i = 0; i < array.length; i++) {\n if (i !== 0) {\n if (i === array.length - 1) {\n list += ' ' + finalDelimiter + ' '\n } else {\n list += delimiter + ' '\n }\n }\n list += array[i]\n }\n return list\n }\n\n callback =\n callback ||\n function (o) {\n return o.toString()\n }\n\n const realCallback = (arg: ByWeekday) => {\n return callback && callback.call(this, arg)\n }\n\n if (finalDelim) {\n return delimJoin(arr.map(realCallback), delim, finalDelim)\n } else {\n return arr.map(realCallback).join(delim + ' ')\n }\n }\n}\n","import ENGLISH, { Language } from './i18n'\nimport { RRule } from '../rrule'\nimport { ByWeekday, Options } from '../types'\nimport { WeekdayStr } from '../weekday'\n\n// =============================================================================\n// Parser\n// =============================================================================\n\nclass Parser {\n private readonly rules: { [k: string]: RegExp }\n public text: string\n public symbol: string | null\n public value: RegExpExecArray | null\n private done = true\n\n constructor(rules: { [k: string]: RegExp }) {\n this.rules = rules\n }\n\n start(text: string) {\n this.text = text\n this.done = false\n return this.nextSymbol()\n }\n\n isDone() {\n return this.done && this.symbol === null\n }\n\n nextSymbol() {\n let best: RegExpExecArray | null\n let bestSymbol: string\n\n this.symbol = null\n this.value = null\n do {\n if (this.done) return false\n\n let rule: RegExp\n best = null\n for (const name in this.rules) {\n rule = this.rules[name]\n const match = rule.exec(this.text)\n if (match) {\n if (best === null || match[0].length > best[0].length) {\n best = match\n bestSymbol = name\n }\n }\n }\n\n if (best != null) {\n this.text = this.text.substr(best[0].length)\n\n if (this.text === '') this.done = true\n }\n\n if (best == null) {\n this.done = true\n this.symbol = null\n this.value = null\n return\n }\n } while (bestSymbol === 'SKIP')\n\n this.symbol = bestSymbol\n this.value = best\n return true\n }\n\n accept(name: string) {\n if (this.symbol === name) {\n if (this.value) {\n const v = this.value\n this.nextSymbol()\n return v\n }\n\n this.nextSymbol()\n return true\n }\n\n return false\n }\n\n acceptNumber() {\n return this.accept('number') as RegExpExecArray\n }\n\n expect(name: string) {\n if (this.accept(name)) return true\n\n throw new Error('expected ' + name + ' but found ' + this.symbol)\n }\n}\n\nexport default function parseText(text: string, language: Language = ENGLISH) {\n const options: Partial = {}\n const ttr = new Parser(language.tokens)\n\n if (!ttr.start(text)) return null\n\n S()\n return options\n\n function S() {\n // every [n]\n ttr.expect('every')\n const n = ttr.acceptNumber()\n if (n) options.interval = parseInt(n[0], 10)\n if (ttr.isDone()) throw new Error('Unexpected end')\n\n switch (ttr.symbol) {\n case 'day(s)':\n options.freq = RRule.DAILY\n if (ttr.nextSymbol()) {\n AT()\n F()\n }\n break\n\n // FIXME Note: every 2 weekdays != every two weeks on weekdays.\n // DAILY on weekdays is not a valid rule\n case 'weekday(s)':\n options.freq = RRule.WEEKLY\n options.byweekday = [RRule.MO, RRule.TU, RRule.WE, RRule.TH, RRule.FR]\n ttr.nextSymbol()\n AT()\n F()\n break\n\n case 'week(s)':\n options.freq = RRule.WEEKLY\n if (ttr.nextSymbol()) {\n ON()\n AT()\n F()\n }\n break\n\n case 'hour(s)':\n options.freq = RRule.HOURLY\n if (ttr.nextSymbol()) {\n ON()\n F()\n }\n break\n\n case 'minute(s)':\n options.freq = RRule.MINUTELY\n if (ttr.nextSymbol()) {\n ON()\n F()\n }\n break\n\n case 'month(s)':\n options.freq = RRule.MONTHLY\n if (ttr.nextSymbol()) {\n ON()\n F()\n }\n break\n\n case 'year(s)':\n options.freq = RRule.YEARLY\n if (ttr.nextSymbol()) {\n ON()\n F()\n }\n break\n\n case 'monday':\n case 'tuesday':\n case 'wednesday':\n case 'thursday':\n case 'friday':\n case 'saturday':\n case 'sunday':\n options.freq = RRule.WEEKLY\n const key: WeekdayStr = ttr.symbol\n .substr(0, 2)\n .toUpperCase() as WeekdayStr\n options.byweekday = [RRule[key]]\n\n if (!ttr.nextSymbol()) return\n\n // TODO check for duplicates\n while (ttr.accept('comma')) {\n if (ttr.isDone()) throw new Error('Unexpected end')\n\n const wkd = decodeWKD() as keyof typeof RRule\n if (!wkd) {\n throw new Error(\n 'Unexpected symbol ' + ttr.symbol + ', expected weekday'\n )\n }\n\n options.byweekday.push(RRule[wkd] as ByWeekday)\n ttr.nextSymbol()\n }\n AT()\n MDAYs()\n F()\n break\n\n case 'january':\n case 'february':\n case 'march':\n case 'april':\n case 'may':\n case 'june':\n case 'july':\n case 'august':\n case 'september':\n case 'october':\n case 'november':\n case 'december':\n options.freq = RRule.YEARLY\n options.bymonth = [decodeM() as number]\n\n if (!ttr.nextSymbol()) return\n\n // TODO check for duplicates\n while (ttr.accept('comma')) {\n if (ttr.isDone()) throw new Error('Unexpected end')\n\n const m = decodeM()\n if (!m) {\n throw new Error(\n 'Unexpected symbol ' + ttr.symbol + ', expected month'\n )\n }\n\n options.bymonth.push(m)\n ttr.nextSymbol()\n }\n\n ON()\n F()\n break\n\n default:\n throw new Error('Unknown symbol')\n }\n }\n\n function ON() {\n const on = ttr.accept('on')\n const the = ttr.accept('the')\n if (!(on || the)) return\n\n do {\n const nth = decodeNTH()\n const wkd = decodeWKD()\n const m = decodeM()\n\n // nth | \n if (nth) {\n // ttr.nextSymbol()\n\n if (wkd) {\n ttr.nextSymbol()\n if (!options.byweekday) options.byweekday = [] as ByWeekday[]\n ;(options.byweekday as ByWeekday[]).push(\n RRule[wkd as WeekdayStr].nth(nth)\n )\n } else {\n if (!options.bymonthday) options.bymonthday = [] as number[]\n ;(options.bymonthday as number[]).push(nth)\n ttr.accept('day(s)')\n }\n // \n } else if (wkd) {\n ttr.nextSymbol()\n if (!options.byweekday) options.byweekday = [] as ByWeekday[]\n ;(options.byweekday as ByWeekday[]).push(RRule[wkd as WeekdayStr])\n } else if (ttr.symbol === 'weekday(s)') {\n ttr.nextSymbol()\n if (!options.byweekday) {\n options.byweekday = [RRule.MO, RRule.TU, RRule.WE, RRule.TH, RRule.FR]\n }\n } else if (ttr.symbol === 'week(s)') {\n ttr.nextSymbol()\n let n = ttr.acceptNumber()\n if (!n) {\n throw new Error(\n 'Unexpected symbol ' + ttr.symbol + ', expected week number'\n )\n }\n options.byweekno = [parseInt(n[0], 10)]\n while (ttr.accept('comma')) {\n n = ttr.acceptNumber()\n if (!n) {\n throw new Error(\n 'Unexpected symbol ' + ttr.symbol + '; expected monthday'\n )\n }\n options.byweekno.push(parseInt(n[0], 10))\n }\n } else if (m) {\n ttr.nextSymbol()\n if (!options.bymonth) options.bymonth = [] as number[]\n ;(options.bymonth as number[]).push(m)\n } else {\n return\n }\n } while (ttr.accept('comma') || ttr.accept('the') || ttr.accept('on'))\n }\n\n function AT() {\n const at = ttr.accept('at')\n if (!at) return\n\n do {\n let n = ttr.acceptNumber()\n if (!n) {\n throw new Error('Unexpected symbol ' + ttr.symbol + ', expected hour')\n }\n options.byhour = [parseInt(n[0], 10)]\n while (ttr.accept('comma')) {\n n = ttr.acceptNumber()\n if (!n) {\n throw new Error('Unexpected symbol ' + ttr.symbol + '; expected hour')\n }\n options.byhour.push(parseInt(n[0], 10))\n }\n } while (ttr.accept('comma') || ttr.accept('at'))\n }\n\n function decodeM() {\n switch (ttr.symbol) {\n case 'january':\n return 1\n case 'february':\n return 2\n case 'march':\n return 3\n case 'april':\n return 4\n case 'may':\n return 5\n case 'june':\n return 6\n case 'july':\n return 7\n case 'august':\n return 8\n case 'september':\n return 9\n case 'october':\n return 10\n case 'november':\n return 11\n case 'december':\n return 12\n default:\n return false\n }\n }\n\n function decodeWKD() {\n switch (ttr.symbol) {\n case 'monday':\n case 'tuesday':\n case 'wednesday':\n case 'thursday':\n case 'friday':\n case 'saturday':\n case 'sunday':\n return ttr.symbol.substr(0, 2).toUpperCase()\n default:\n return false\n }\n }\n\n function decodeNTH() {\n switch (ttr.symbol) {\n case 'last':\n ttr.nextSymbol()\n return -1\n case 'first':\n ttr.nextSymbol()\n return 1\n case 'second':\n ttr.nextSymbol()\n return ttr.accept('last') ? -2 : 2\n case 'third':\n ttr.nextSymbol()\n return ttr.accept('last') ? -3 : 3\n case 'nth':\n const v = parseInt(ttr.value[1], 10)\n if (v < -366 || v > 366) throw new Error('Nth out of range: ' + v)\n\n ttr.nextSymbol()\n return ttr.accept('last') ? -v : v\n\n default:\n return false\n }\n }\n\n function MDAYs() {\n ttr.accept('on')\n ttr.accept('the')\n\n let nth = decodeNTH()\n if (!nth) return\n\n options.bymonthday = [nth]\n ttr.nextSymbol()\n\n while (ttr.accept('comma')) {\n nth = decodeNTH()\n if (!nth) {\n throw new Error(\n 'Unexpected symbol ' + ttr.symbol + '; expected monthday'\n )\n }\n\n options.bymonthday.push(nth)\n ttr.nextSymbol()\n }\n }\n\n function F() {\n if (ttr.symbol === 'until') {\n const date = Date.parse(ttr.text)\n\n if (!date) throw new Error('Cannot parse until date:' + ttr.text)\n options.until = new Date(date)\n } else if (ttr.accept('for')) {\n options.count = parseInt(ttr.value[0], 10)\n ttr.expect('number')\n // ttr.expect('times')\n }\n }\n}\n","import { Weekday, WeekdayStr } from './weekday'\n\nexport interface QueryMethods {\n all(): Date[]\n between(after: Date, before: Date, inc: boolean): Date[]\n before(date: Date, inc: boolean): Date | null\n after(date: Date, inc: boolean): Date | null\n}\n\nexport type QueryMethodTypes = keyof QueryMethods\nexport type IterResultType = M extends\n | 'all'\n | 'between'\n ? Date[]\n : Date | null\n\nexport enum Frequency {\n YEARLY = 0,\n MONTHLY = 1,\n WEEKLY = 2,\n DAILY = 3,\n HOURLY = 4,\n MINUTELY = 5,\n SECONDLY = 6,\n}\n\nexport function freqIsDailyOrGreater(\n freq: Frequency\n): freq is\n | Frequency.YEARLY\n | Frequency.MONTHLY\n | Frequency.WEEKLY\n | Frequency.DAILY {\n return freq < Frequency.HOURLY\n}\n\nexport interface Options {\n freq: Frequency\n dtstart: Date | null\n interval: number\n wkst: Weekday | number | null\n count: number | null\n until: Date | null\n tzid: string | null\n bysetpos: number | number[] | null\n bymonth: number | number[] | null\n bymonthday: number | number[] | null\n bynmonthday: number[] | null\n byyearday: number | number[] | null\n byweekno: number | number[] | null\n byweekday: ByWeekday | ByWeekday[] | null\n bynweekday: number[][] | null\n byhour: number | number[] | null\n byminute: number | number[] | null\n bysecond: number | number[] | null\n byeaster: number | null\n}\n\nexport interface ParsedOptions extends Options {\n dtstart: Date\n wkst: number\n bysetpos: number[]\n bymonth: number[]\n bymonthday: number[]\n bynmonthday: number[]\n byyearday: number[]\n byweekno: number[]\n byweekday: number[]\n byhour: number[]\n byminute: number[]\n bysecond: number[]\n}\n\nexport type ByWeekday = WeekdayStr | number | Weekday\n","import ToText, { DateFormatter, GetText } from './totext'\nimport parseText from './parsetext'\nimport { RRule } from '../rrule'\nimport { Frequency } from '../types'\nimport ENGLISH, { Language } from './i18n'\n\n/* !\n * rrule.js - Library for working with recurrence rules for calendar dates.\n * https://github.com/jakubroztocil/rrule\n *\n * Copyright 2010, Jakub Roztocil and Lars Schoning\n * Licenced under the BSD licence.\n * https://github.com/jakubroztocil/rrule/blob/master/LICENCE\n *\n */\n\n/**\n *\n * Implementation of RRule.fromText() and RRule::toText().\n *\n *\n * On the client side, this file needs to be included\n * when those functions are used.\n *\n */\n\n// =============================================================================\n// fromText\n// =============================================================================\n/**\n * Will be able to convert some of the below described rules from\n * text format to a rule object.\n *\n *\n * RULES\n *\n * Every ([n])\n * day(s)\n * | [weekday], ..., (and) [weekday]\n * | weekday(s)\n * | week(s)\n * | month(s)\n * | [month], ..., (and) [month]\n * | year(s)\n *\n *\n * Plus 0, 1, or multiple of these:\n *\n * on [weekday], ..., (or) [weekday] the [monthday], [monthday], ... (or) [monthday]\n *\n * on [weekday], ..., (and) [weekday]\n *\n * on the [monthday], [monthday], ... (and) [monthday] (day of the month)\n *\n * on the [nth-weekday], ..., (and) [nth-weekday] (of the month/year)\n *\n *\n * Plus 0 or 1 of these:\n *\n * for [n] time(s)\n *\n * until [date]\n *\n * Plus (.)\n *\n *\n * Definitely no supported for parsing:\n *\n * (for year):\n * in week(s) [n], ..., (and) [n]\n *\n * on the [yearday], ..., (and) [n] day of the year\n * on day [yearday], ..., (and) [n]\n *\n *\n * NON-TERMINALS\n *\n * [n]: 1, 2 ..., one, two, three ..\n * [month]: January, February, March, April, May, ... December\n * [weekday]: Monday, ... Sunday\n * [nth-weekday]: first [weekday], 2nd [weekday], ... last [weekday], ...\n * [monthday]: first, 1., 2., 1st, 2nd, second, ... 31st, last day, 2nd last day, ..\n * [date]:\n * - [month] (0-31(,) ([year])),\n * - (the) 0-31.(1-12.([year])),\n * - (the) 0-31/(1-12/([year])),\n * - [weekday]\n *\n * [year]: 0000, 0001, ... 01, 02, ..\n *\n * Definitely not supported for parsing:\n *\n * [yearday]: first, 1., 2., 1st, 2nd, second, ... 366th, last day, 2nd last day, ..\n *\n * @param {String} text\n * @return {Object, Boolean} the rule, or null.\n */\nconst fromText = function (text: string, language: Language = ENGLISH) {\n return new RRule(parseText(text, language) || undefined)\n}\n\nconst common = [\n 'count',\n 'until',\n 'interval',\n 'byweekday',\n 'bymonthday',\n 'bymonth',\n]\n\nToText.IMPLEMENTED = []\nToText.IMPLEMENTED[Frequency.HOURLY] = common\nToText.IMPLEMENTED[Frequency.MINUTELY] = common\nToText.IMPLEMENTED[Frequency.DAILY] = ['byhour'].concat(common)\nToText.IMPLEMENTED[Frequency.WEEKLY] = common\nToText.IMPLEMENTED[Frequency.MONTHLY] = common\nToText.IMPLEMENTED[Frequency.YEARLY] = ['byweekno', 'byyearday'].concat(common)\n\n// =============================================================================\n// Export\n// =============================================================================\n\nconst toText = function (\n rrule: RRule,\n gettext?: GetText,\n language?: Language,\n dateFormatter?: DateFormatter\n) {\n return new ToText(rrule, gettext, language, dateFormatter).toString()\n}\n\nconst { isFullyConvertible } = ToText\n\nexport interface Nlp {\n fromText: typeof fromText\n parseText: typeof parseText\n isFullyConvertible: typeof isFullyConvertible\n toText: typeof toText\n}\n\nexport { fromText, parseText, isFullyConvertible, toText }\n","import { ParsedOptions, Frequency } from './types'\nimport { pymod, divmod, empty, includes } from './helpers'\nimport { getWeekday, MAXYEAR, monthRange } from './dateutil'\n\nexport class Time {\n public hour: number\n public minute: number\n public second: number\n public millisecond: number\n\n constructor(\n hour: number,\n minute: number,\n second: number,\n millisecond: number\n ) {\n this.hour = hour\n this.minute = minute\n this.second = second\n this.millisecond = millisecond || 0\n }\n\n getHours() {\n return this.hour\n }\n\n getMinutes() {\n return this.minute\n }\n\n getSeconds() {\n return this.second\n }\n\n getMilliseconds() {\n return this.millisecond\n }\n\n getTime() {\n return (\n (this.hour * 60 * 60 + this.minute * 60 + this.second) * 1000 +\n this.millisecond\n )\n }\n}\n\nexport class DateTime extends Time {\n public day: number\n public month: number\n public year: number\n\n static fromDate(date: Date) {\n return new this(\n date.getUTCFullYear(),\n date.getUTCMonth() + 1,\n date.getUTCDate(),\n date.getUTCHours(),\n date.getUTCMinutes(),\n date.getUTCSeconds(),\n date.valueOf() % 1000\n )\n }\n\n constructor(\n year: number,\n month: number,\n day: number,\n hour: number,\n minute: number,\n second: number,\n millisecond: number\n ) {\n super(hour, minute, second, millisecond)\n this.year = year\n this.month = month\n this.day = day\n }\n\n getWeekday() {\n return getWeekday(new Date(this.getTime()))\n }\n\n getTime() {\n return new Date(\n Date.UTC(\n this.year,\n this.month - 1,\n this.day,\n this.hour,\n this.minute,\n this.second,\n this.millisecond\n )\n ).getTime()\n }\n\n getDay() {\n return this.day\n }\n\n getMonth() {\n return this.month\n }\n\n getYear() {\n return this.year\n }\n\n public addYears(years: number) {\n this.year += years\n }\n\n public addMonths(months: number) {\n this.month += months\n if (this.month > 12) {\n const yearDiv = Math.floor(this.month / 12)\n const monthMod = pymod(this.month, 12)\n this.month = monthMod\n this.year += yearDiv\n if (this.month === 0) {\n this.month = 12\n --this.year\n }\n }\n }\n\n public addWeekly(days: number, wkst: number) {\n if (wkst > this.getWeekday()) {\n this.day += -(this.getWeekday() + 1 + (6 - wkst)) + days * 7\n } else {\n this.day += -(this.getWeekday() - wkst) + days * 7\n }\n\n this.fixDay()\n }\n\n public addDaily(days: number) {\n this.day += days\n this.fixDay()\n }\n\n public addHours(hours: number, filtered: boolean, byhour: number[]) {\n if (filtered) {\n // Jump to one iteration before next day\n this.hour += Math.floor((23 - this.hour) / hours) * hours\n }\n\n for (;;) {\n this.hour += hours\n const { div: dayDiv, mod: hourMod } = divmod(this.hour, 24)\n if (dayDiv) {\n this.hour = hourMod\n this.addDaily(dayDiv)\n }\n\n if (empty(byhour) || includes(byhour, this.hour)) break\n }\n }\n\n public addMinutes(\n minutes: number,\n filtered: boolean,\n byhour: number[],\n byminute: number[]\n ) {\n if (filtered) {\n // Jump to one iteration before next day\n this.minute +=\n Math.floor((1439 - (this.hour * 60 + this.minute)) / minutes) * minutes\n }\n\n for (;;) {\n this.minute += minutes\n const { div: hourDiv, mod: minuteMod } = divmod(this.minute, 60)\n if (hourDiv) {\n this.minute = minuteMod\n this.addHours(hourDiv, false, byhour)\n }\n\n if (\n (empty(byhour) || includes(byhour, this.hour)) &&\n (empty(byminute) || includes(byminute, this.minute))\n ) {\n break\n }\n }\n }\n\n public addSeconds(\n seconds: number,\n filtered: boolean,\n byhour: number[],\n byminute: number[],\n bysecond: number[]\n ) {\n if (filtered) {\n // Jump to one iteration before next day\n this.second +=\n Math.floor(\n (86399 - (this.hour * 3600 + this.minute * 60 + this.second)) /\n seconds\n ) * seconds\n }\n\n for (;;) {\n this.second += seconds\n const { div: minuteDiv, mod: secondMod } = divmod(this.second, 60)\n if (minuteDiv) {\n this.second = secondMod\n this.addMinutes(minuteDiv, false, byhour, byminute)\n }\n\n if (\n (empty(byhour) || includes(byhour, this.hour)) &&\n (empty(byminute) || includes(byminute, this.minute)) &&\n (empty(bysecond) || includes(bysecond, this.second))\n ) {\n break\n }\n }\n }\n\n public fixDay() {\n if (this.day <= 28) {\n return\n }\n\n let daysinmonth = monthRange(this.year, this.month - 1)[1]\n if (this.day <= daysinmonth) {\n return\n }\n\n while (this.day > daysinmonth) {\n this.day -= daysinmonth\n ++this.month\n if (this.month === 13) {\n this.month = 1\n ++this.year\n if (this.year > MAXYEAR) {\n return\n }\n }\n\n daysinmonth = monthRange(this.year, this.month - 1)[1]\n }\n }\n\n public add(options: ParsedOptions, filtered: boolean) {\n const { freq, interval, wkst, byhour, byminute, bysecond } = options\n\n switch (freq) {\n case Frequency.YEARLY:\n return this.addYears(interval)\n case Frequency.MONTHLY:\n return this.addMonths(interval)\n case Frequency.WEEKLY:\n return this.addWeekly(interval, wkst)\n case Frequency.DAILY:\n return this.addDaily(interval)\n case Frequency.HOURLY:\n return this.addHours(interval, filtered, byhour)\n case Frequency.MINUTELY:\n return this.addMinutes(interval, filtered, byhour, byminute)\n case Frequency.SECONDLY:\n return this.addSeconds(interval, filtered, byhour, byminute, bysecond)\n }\n }\n}\n","import { Options, ParsedOptions, freqIsDailyOrGreater } from './types'\nimport {\n includes,\n notEmpty,\n isPresent,\n isNumber,\n isArray,\n isWeekdayStr,\n} from './helpers'\nimport { RRule, defaultKeys, DEFAULT_OPTIONS } from './rrule'\nimport { getWeekday, isDate, isValidDate } from './dateutil'\nimport { Weekday } from './weekday'\nimport { Time } from './datetime'\n\nexport function initializeOptions(options: Partial) {\n const invalid: string[] = []\n const keys = Object.keys(options) as (keyof Options)[]\n\n // Shallow copy for options and origOptions and check for invalid\n for (const key of keys) {\n if (!includes(defaultKeys, key)) invalid.push(key)\n if (isDate(options[key]) && !isValidDate(options[key])) {\n invalid.push(key)\n }\n }\n\n if (invalid.length) {\n throw new Error('Invalid options: ' + invalid.join(', '))\n }\n\n return { ...options }\n}\n\nexport function parseOptions(options: Partial) {\n const opts = { ...DEFAULT_OPTIONS, ...initializeOptions(options) }\n\n if (isPresent(opts.byeaster)) opts.freq = RRule.YEARLY\n\n if (!(isPresent(opts.freq) && RRule.FREQUENCIES[opts.freq])) {\n throw new Error(`Invalid frequency: ${opts.freq} ${options.freq}`)\n }\n\n if (!opts.dtstart) opts.dtstart = new Date(new Date().setMilliseconds(0))\n\n if (!isPresent(opts.wkst)) {\n opts.wkst = RRule.MO.weekday\n } else if (isNumber(opts.wkst)) {\n // cool, just keep it like that\n } else {\n opts.wkst = opts.wkst.weekday\n }\n\n if (isPresent(opts.bysetpos)) {\n if (isNumber(opts.bysetpos)) opts.bysetpos = [opts.bysetpos]\n\n for (let i = 0; i < opts.bysetpos.length; i++) {\n const v = opts.bysetpos[i]\n if (v === 0 || !(v >= -366 && v <= 366)) {\n throw new Error(\n 'bysetpos must be between 1 and 366,' + ' or between -366 and -1'\n )\n }\n }\n }\n\n if (\n !(\n Boolean(opts.byweekno as number) ||\n notEmpty(opts.byweekno as number[]) ||\n notEmpty(opts.byyearday as number[]) ||\n Boolean(opts.bymonthday) ||\n notEmpty(opts.bymonthday as number[]) ||\n isPresent(opts.byweekday) ||\n isPresent(opts.byeaster)\n )\n ) {\n switch (opts.freq) {\n case RRule.YEARLY:\n if (!opts.bymonth) opts.bymonth = opts.dtstart.getUTCMonth() + 1\n opts.bymonthday = opts.dtstart.getUTCDate()\n break\n case RRule.MONTHLY:\n opts.bymonthday = opts.dtstart.getUTCDate()\n break\n case RRule.WEEKLY:\n opts.byweekday = [getWeekday(opts.dtstart)]\n break\n }\n }\n\n // bymonth\n if (isPresent(opts.bymonth) && !isArray(opts.bymonth)) {\n opts.bymonth = [opts.bymonth]\n }\n\n // byyearday\n if (\n isPresent(opts.byyearday) &&\n !isArray(opts.byyearday) &&\n isNumber(opts.byyearday)\n ) {\n opts.byyearday = [opts.byyearday]\n }\n\n // bymonthday\n if (!isPresent(opts.bymonthday)) {\n opts.bymonthday = []\n opts.bynmonthday = []\n } else if (isArray(opts.bymonthday)) {\n const bymonthday = []\n const bynmonthday = []\n\n for (let i = 0; i < opts.bymonthday.length; i++) {\n const v = opts.bymonthday[i]\n if (v > 0) {\n bymonthday.push(v)\n } else if (v < 0) {\n bynmonthday.push(v)\n }\n }\n opts.bymonthday = bymonthday\n opts.bynmonthday = bynmonthday\n } else if (opts.bymonthday < 0) {\n opts.bynmonthday = [opts.bymonthday]\n opts.bymonthday = []\n } else {\n opts.bynmonthday = []\n opts.bymonthday = [opts.bymonthday]\n }\n\n // byweekno\n if (isPresent(opts.byweekno) && !isArray(opts.byweekno)) {\n opts.byweekno = [opts.byweekno]\n }\n\n // byweekday / bynweekday\n if (!isPresent(opts.byweekday)) {\n opts.bynweekday = null\n } else if (isNumber(opts.byweekday)) {\n opts.byweekday = [opts.byweekday]\n opts.bynweekday = null\n } else if (isWeekdayStr(opts.byweekday)) {\n opts.byweekday = [Weekday.fromStr(opts.byweekday).weekday]\n opts.bynweekday = null\n } else if (opts.byweekday instanceof Weekday) {\n if (!opts.byweekday.n || opts.freq > RRule.MONTHLY) {\n opts.byweekday = [opts.byweekday.weekday]\n opts.bynweekday = null\n } else {\n opts.bynweekday = [[opts.byweekday.weekday, opts.byweekday.n]]\n opts.byweekday = null\n }\n } else {\n const byweekday: number[] = []\n const bynweekday = []\n\n for (let i = 0; i < opts.byweekday.length; i++) {\n const wday = opts.byweekday[i]\n\n if (isNumber(wday)) {\n byweekday.push(wday)\n continue\n } else if (isWeekdayStr(wday)) {\n byweekday.push(Weekday.fromStr(wday).weekday)\n continue\n }\n\n if (!wday.n || opts.freq > RRule.MONTHLY) {\n byweekday.push(wday.weekday)\n } else {\n bynweekday.push([wday.weekday, wday.n])\n }\n }\n opts.byweekday = notEmpty(byweekday) ? byweekday : null\n opts.bynweekday = notEmpty(bynweekday) ? bynweekday : null\n }\n\n // byhour\n if (!isPresent(opts.byhour)) {\n opts.byhour = opts.freq < RRule.HOURLY ? [opts.dtstart.getUTCHours()] : null\n } else if (isNumber(opts.byhour)) {\n opts.byhour = [opts.byhour]\n }\n\n // byminute\n if (!isPresent(opts.byminute)) {\n opts.byminute =\n opts.freq < RRule.MINUTELY ? [opts.dtstart.getUTCMinutes()] : null\n } else if (isNumber(opts.byminute)) {\n opts.byminute = [opts.byminute]\n }\n\n // bysecond\n if (!isPresent(opts.bysecond)) {\n opts.bysecond =\n opts.freq < RRule.SECONDLY ? [opts.dtstart.getUTCSeconds()] : null\n } else if (isNumber(opts.bysecond)) {\n opts.bysecond = [opts.bysecond]\n }\n\n return { parsedOptions: opts as ParsedOptions }\n}\n\nexport function buildTimeset(opts: ParsedOptions) {\n const millisecondModulo = opts.dtstart.getTime() % 1000\n if (!freqIsDailyOrGreater(opts.freq)) {\n return []\n }\n\n const timeset: Time[] = []\n opts.byhour.forEach((hour) => {\n opts.byminute.forEach((minute) => {\n opts.bysecond.forEach((second) => {\n timeset.push(new Time(hour, minute, second, millisecondModulo))\n })\n })\n })\n\n return timeset\n}\n","import { Options, Frequency } from './types'\nimport { Weekday } from './weekday'\nimport { untilStringToDate } from './dateutil'\nimport { Days } from './rrule'\n\nexport function parseString(rfcString: string): Partial {\n const options = rfcString\n .split('\\n')\n .map(parseLine)\n .filter((x) => x !== null)\n return { ...options[0], ...options[1] }\n}\n\nexport function parseDtstart(line: string) {\n const options: Partial = {}\n\n const dtstartWithZone = /DTSTART(?:;TZID=([^:=]+?))?(?::|=)([^;\\s]+)/i.exec(\n line\n )\n\n if (!dtstartWithZone) {\n return options\n }\n\n const [, tzid, dtstart] = dtstartWithZone\n\n if (tzid) {\n options.tzid = tzid\n }\n options.dtstart = untilStringToDate(dtstart)\n return options\n}\n\nfunction parseLine(rfcString: string) {\n rfcString = rfcString.replace(/^\\s+|\\s+$/, '')\n if (!rfcString.length) return null\n\n const header = /^([A-Z]+?)[:;]/.exec(rfcString.toUpperCase())\n if (!header) {\n return parseRrule(rfcString)\n }\n\n const [, key] = header\n switch (key.toUpperCase()) {\n case 'RRULE':\n case 'EXRULE':\n return parseRrule(rfcString)\n case 'DTSTART':\n return parseDtstart(rfcString)\n default:\n throw new Error(`Unsupported RFC prop ${key} in ${rfcString}`)\n }\n}\n\nfunction parseRrule(line: string) {\n const strippedLine = line.replace(/^RRULE:/i, '')\n const options = parseDtstart(strippedLine)\n\n const attrs = line.replace(/^(?:RRULE|EXRULE):/i, '').split(';')\n\n attrs.forEach((attr) => {\n const [key, value] = attr.split('=')\n switch (key.toUpperCase()) {\n case 'FREQ':\n options.freq = Frequency[value.toUpperCase() as keyof typeof Frequency]\n break\n case 'WKST':\n options.wkst = Days[value.toUpperCase() as keyof typeof Days]\n break\n case 'COUNT':\n case 'INTERVAL':\n case 'BYSETPOS':\n case 'BYMONTH':\n case 'BYMONTHDAY':\n case 'BYYEARDAY':\n case 'BYWEEKNO':\n case 'BYHOUR':\n case 'BYMINUTE':\n case 'BYSECOND':\n const num = parseNumber(value)\n const optionKey = key.toLowerCase()\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n options[optionKey] = num\n break\n case 'BYWEEKDAY':\n case 'BYDAY':\n options.byweekday = parseWeekday(value)\n break\n case 'DTSTART':\n case 'TZID':\n // for backwards compatibility\n const dtstart = parseDtstart(line)\n options.tzid = dtstart.tzid\n options.dtstart = dtstart.dtstart\n break\n case 'UNTIL':\n options.until = untilStringToDate(value)\n break\n case 'BYEASTER':\n options.byeaster = Number(value)\n break\n default:\n throw new Error(\"Unknown RRULE property '\" + key + \"'\")\n }\n })\n\n return options\n}\n\nfunction parseNumber(value: string) {\n if (value.indexOf(',') !== -1) {\n const values = value.split(',')\n return values.map(parseIndividualNumber)\n }\n\n return parseIndividualNumber(value)\n}\n\nfunction parseIndividualNumber(value: string) {\n if (/^[+-]?\\d+$/.test(value)) {\n return Number(value)\n }\n\n return value\n}\n\nfunction parseWeekday(value: string) {\n const days = value.split(',')\n\n return days.map((day) => {\n if (day.length === 2) {\n // MO, TU, ...\n return Days[day as keyof typeof Days] // wday instanceof Weekday\n }\n\n // -1MO, +3FR, 1SO, 13TU ...\n const parts = day.match(/^([+-]?\\d{1,2})([A-Z]{2})$/)\n if (!parts || parts.length < 3) {\n throw new SyntaxError(`Invalid weekday string: ${day}`)\n }\n const n = Number(parts[1])\n const wdaypart = parts[2] as keyof typeof Days\n const wday = Days[wdaypart].weekday\n return new Weekday(wday, n)\n })\n}\n","import { dateInTimeZone, timeToUntilString } from './dateutil'\n\nexport class DateWithZone {\n public date: Date\n public tzid?: string | null\n\n constructor(date: Date, tzid?: string | null) {\n if (isNaN(date.getTime())) {\n throw new RangeError('Invalid date passed to DateWithZone')\n }\n this.date = date\n this.tzid = tzid\n }\n\n private get isUTC() {\n return !this.tzid || this.tzid.toUpperCase() === 'UTC'\n }\n\n public toString() {\n const datestr = timeToUntilString(this.date.getTime(), this.isUTC)\n if (!this.isUTC) {\n return `;TZID=${this.tzid}:${datestr}`\n }\n\n return `:${datestr}`\n }\n\n public getTime() {\n return this.date.getTime()\n }\n\n public rezonedDate() {\n if (this.isUTC) {\n return this.date\n }\n\n return dateInTimeZone(this.date, this.tzid)\n }\n}\n","import { Options } from './types'\nimport { RRule, DEFAULT_OPTIONS } from './rrule'\nimport { includes, isPresent, isArray, isNumber, toArray } from './helpers'\nimport { Weekday } from './weekday'\nimport { timeToUntilString } from './dateutil'\nimport { DateWithZone } from './datewithzone'\n\nexport function optionsToString(options: Partial) {\n const rrule: string[][] = []\n let dtstart = ''\n const keys: (keyof Options)[] = Object.keys(options) as (keyof Options)[]\n const defaultKeys = Object.keys(DEFAULT_OPTIONS)\n\n for (let i = 0; i < keys.length; i++) {\n if (keys[i] === 'tzid') continue\n if (!includes(defaultKeys, keys[i])) continue\n\n let key = keys[i].toUpperCase()\n const value = options[keys[i]]\n let outValue = ''\n\n if (!isPresent(value) || (isArray(value) && !value.length)) continue\n\n switch (key) {\n case 'FREQ':\n outValue = RRule.FREQUENCIES[options.freq]\n break\n case 'WKST':\n if (isNumber(value)) {\n outValue = new Weekday(value).toString()\n } else {\n outValue = value.toString()\n }\n break\n case 'BYWEEKDAY':\n /*\n NOTE: BYWEEKDAY is a special case.\n RRule() deconstructs the rule.options.byweekday array\n into an array of Weekday arguments.\n On the other hand, rule.origOptions is an array of Weekdays.\n We need to handle both cases here.\n It might be worth change RRule to keep the Weekdays.\n\n Also, BYWEEKDAY (used by RRule) vs. BYDAY (RFC)\n\n */\n key = 'BYDAY'\n outValue = toArray(\n value as Weekday | number[] | number\n )\n .map((wday) => {\n if (wday instanceof Weekday) {\n return wday\n }\n\n if (isArray(wday)) {\n return new Weekday(wday[0], wday[1])\n }\n\n return new Weekday(wday)\n })\n .toString()\n\n break\n case 'DTSTART':\n dtstart = buildDtstart(value as number, options.tzid)\n break\n\n case 'UNTIL':\n outValue = timeToUntilString(value as number, !options.tzid)\n break\n\n default:\n if (isArray(value)) {\n const strValues: string[] = []\n for (let j = 0; j < value.length; j++) {\n strValues[j] = String(value[j])\n }\n outValue = strValues.toString()\n } else {\n outValue = String(value)\n }\n }\n\n if (outValue) {\n rrule.push([key, outValue])\n }\n }\n\n const rules = rrule\n .map(([key, value]) => `${key}=${value.toString()}`)\n .join(';')\n let ruleString = ''\n if (rules !== '') {\n ruleString = `RRULE:${rules}`\n }\n\n return [dtstart, ruleString].filter((x) => !!x).join('\\n')\n}\n\nfunction buildDtstart(dtstart?: number, tzid?: string | null) {\n if (!dtstart) {\n return ''\n }\n\n return 'DTSTART' + new DateWithZone(new Date(dtstart), tzid).toString()\n}\n","import IterResult, { IterArgs } from './iterresult'\nimport { clone, cloneDates } from './dateutil'\nimport { isArray } from './helpers'\n\nexport type CacheKeys = 'before' | 'after' | 'between'\n\nfunction argsMatch(\n left: IterArgs[keyof IterArgs] | undefined,\n right: IterArgs[keyof IterArgs] | undefined\n) {\n if (Array.isArray(left)) {\n if (!Array.isArray(right)) return false\n if (left.length !== right.length) return false\n return left.every((date, i) => date.getTime() === right[i].getTime())\n }\n\n if (left instanceof Date) {\n return right instanceof Date && left.getTime() === right.getTime()\n }\n\n return left === right\n}\n\nexport class Cache {\n all: Date[] | Partial | false = false\n before: IterArgs[] = []\n after: IterArgs[] = []\n between: IterArgs[] = []\n\n /**\n * @param {String} what - all/before/after/between\n * @param {Array,Date} value - an array of dates, one date, or null\n * @param {Object?} args - _iter arguments\n */\n public _cacheAdd(\n what: CacheKeys | 'all',\n value: Date[] | Date | null,\n args?: Partial\n ) {\n if (value) {\n value = value instanceof Date ? clone(value) : cloneDates(value)\n }\n\n if (what === 'all') {\n this.all = value as Date[]\n } else {\n args._value = value\n this[what].push(args as IterArgs)\n }\n }\n\n /**\n * @return false - not in the cache\n * @return null - cached, but zero occurrences (before/after)\n * @return Date - cached (before/after)\n * @return [] - cached, but zero occurrences (all/between)\n * @return [Date1, DateN] - cached (all/between)\n */\n public _cacheGet(\n what: CacheKeys | 'all',\n args?: Partial\n ): Date | Date[] | false | null {\n let cached: Date | Date[] | false | null = false\n const argsKeys = args ? (Object.keys(args) as (keyof IterArgs)[]) : []\n const findCacheDiff = function (item: IterArgs) {\n for (let i = 0; i < argsKeys.length; i++) {\n const key = argsKeys[i]\n if (!argsMatch(args[key], item[key])) {\n return true\n }\n }\n return false\n }\n\n const cachedObject = this[what]\n if (what === 'all') {\n cached = this.all as Date[]\n } else if (isArray(cachedObject)) {\n // Let's see whether we've already called the\n // 'what' method with the same 'args'\n for (let i = 0; i < cachedObject.length; i++) {\n const item = cachedObject[i] as IterArgs\n if (argsKeys.length && findCacheDiff(item)) continue\n cached = item._value\n break\n }\n }\n\n if (!cached && this.all) {\n // Not in the cache, but we already know all the occurrences,\n // so we can find the correct dates from the cached ones.\n const iterResult = new IterResult(what, args)\n for (let i = 0; i < (this.all as Date[]).length; i++) {\n if (!iterResult.accept((this.all as Date[])[i])) break\n }\n cached = iterResult.getValue() as Date\n this._cacheAdd(what, cached, args)\n }\n\n return isArray(cached)\n ? cloneDates(cached)\n : cached instanceof Date\n ? clone(cached)\n : cached\n }\n}\n","import { range, repeat } from './helpers'\n\n// =============================================================================\n// Date masks\n// =============================================================================\n\n// Every mask is 7 days longer to handle cross-year weekly periods.\n\nconst M365MASK = [\n ...repeat(1, 31),\n ...repeat(2, 28),\n ...repeat(3, 31),\n ...repeat(4, 30),\n ...repeat(5, 31),\n ...repeat(6, 30),\n ...repeat(7, 31),\n ...repeat(8, 31),\n ...repeat(9, 30),\n ...repeat(10, 31),\n ...repeat(11, 30),\n ...repeat(12, 31),\n ...repeat(1, 7),\n]\n\nconst M366MASK = [\n ...repeat(1, 31),\n ...repeat(2, 29),\n ...repeat(3, 31),\n ...repeat(4, 30),\n ...repeat(5, 31),\n ...repeat(6, 30),\n ...repeat(7, 31),\n ...repeat(8, 31),\n ...repeat(9, 30),\n ...repeat(10, 31),\n ...repeat(11, 30),\n ...repeat(12, 31),\n ...repeat(1, 7),\n]\n\nconst M28 = range(1, 29)\nconst M29 = range(1, 30)\nconst M30 = range(1, 31)\nconst M31 = range(1, 32)\n\nconst MDAY366MASK = [\n ...M31,\n ...M29,\n ...M31,\n ...M30,\n ...M31,\n ...M30,\n ...M31,\n ...M31,\n ...M30,\n ...M31,\n ...M30,\n ...M31,\n ...M31.slice(0, 7),\n]\n\nconst MDAY365MASK = [\n ...M31,\n ...M28,\n ...M31,\n ...M30,\n ...M31,\n ...M30,\n ...M31,\n ...M31,\n ...M30,\n ...M31,\n ...M30,\n ...M31,\n ...M31.slice(0, 7),\n]\n\nconst NM28 = range(-28, 0)\nconst NM29 = range(-29, 0)\nconst NM30 = range(-30, 0)\nconst NM31 = range(-31, 0)\n\nconst NMDAY366MASK = [\n ...NM31,\n ...NM29,\n ...NM31,\n ...NM30,\n ...NM31,\n ...NM30,\n ...NM31,\n ...NM31,\n ...NM30,\n ...NM31,\n ...NM30,\n ...NM31,\n ...NM31.slice(0, 7),\n]\n\nconst NMDAY365MASK = [\n ...NM31,\n ...NM28,\n ...NM31,\n ...NM30,\n ...NM31,\n ...NM30,\n ...NM31,\n ...NM31,\n ...NM30,\n ...NM31,\n ...NM30,\n ...NM31,\n ...NM31.slice(0, 7),\n]\n\nconst M366RANGE = [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366]\nconst M365RANGE = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365]\n\nconst WDAYMASK = (function () {\n let wdaymask: number[] = []\n for (let i = 0; i < 55; i++) wdaymask = wdaymask.concat(range(7))\n return wdaymask\n})()\n\nexport {\n WDAYMASK,\n M365MASK,\n M365RANGE,\n M366MASK,\n M366RANGE,\n MDAY365MASK,\n MDAY366MASK,\n NMDAY365MASK,\n NMDAY366MASK,\n}\n","import { ParsedOptions } from '../types'\nimport { datetime, getWeekday, isLeapYear, toOrdinal } from '../dateutil'\nimport { empty, repeat, pymod, includes } from '../helpers'\nimport {\n M365MASK,\n MDAY365MASK,\n NMDAY365MASK,\n WDAYMASK,\n M365RANGE,\n M366MASK,\n MDAY366MASK,\n NMDAY366MASK,\n M366RANGE,\n} from '../masks'\n\nexport interface YearInfo {\n yearlen: 365 | 366\n nextyearlen: 365 | 366\n yearordinal: number\n yearweekday: number\n mmask: number[]\n mrange: number[]\n mdaymask: number[]\n nmdaymask: number[]\n wdaymask: number[]\n wnomask: number[] | null\n}\n\nexport function rebuildYear(year: number, options: ParsedOptions) {\n const firstyday = datetime(year, 1, 1)\n\n const yearlen = isLeapYear(year) ? 366 : 365\n const nextyearlen = isLeapYear(year + 1) ? 366 : 365\n const yearordinal = toOrdinal(firstyday)\n const yearweekday = getWeekday(firstyday)\n\n const result: YearInfo = {\n yearlen,\n nextyearlen,\n yearordinal,\n yearweekday,\n ...baseYearMasks(year),\n wnomask: null,\n }\n\n if (empty(options.byweekno)) {\n return result\n }\n\n result.wnomask = repeat(0, yearlen + 7) as number[]\n let firstwkst: number\n let wyearlen: number\n let no1wkst = (firstwkst = pymod(7 - yearweekday + options.wkst, 7))\n\n if (no1wkst >= 4) {\n no1wkst = 0\n // Number of days in the year, plus the days we got\n // from last year.\n wyearlen = result.yearlen + pymod(yearweekday - options.wkst, 7)\n } else {\n // Number of days in the year, minus the days we\n // left in last year.\n wyearlen = yearlen - no1wkst\n }\n\n const div = Math.floor(wyearlen / 7)\n const mod = pymod(wyearlen, 7)\n const numweeks = Math.floor(div + mod / 4)\n\n for (let j = 0; j < options.byweekno.length; j++) {\n let n = options.byweekno[j]\n if (n < 0) {\n n += numweeks + 1\n }\n if (!(n > 0 && n <= numweeks)) {\n continue\n }\n\n let i: number\n if (n > 1) {\n i = no1wkst + (n - 1) * 7\n if (no1wkst !== firstwkst) {\n i -= 7 - firstwkst\n }\n } else {\n i = no1wkst\n }\n\n for (let k = 0; k < 7; k++) {\n result.wnomask[i] = 1\n i++\n if (result.wdaymask[i] === options.wkst) break\n }\n }\n\n if (includes(options.byweekno, 1)) {\n // Check week number 1 of next year as well\n // orig-TODO : Check -numweeks for next year.\n let i = no1wkst + numweeks * 7\n if (no1wkst !== firstwkst) i -= 7 - firstwkst\n if (i < yearlen) {\n // If week starts in next year, we\n // don't care about it.\n for (let j = 0; j < 7; j++) {\n result.wnomask[i] = 1\n i += 1\n if (result.wdaymask[i] === options.wkst) break\n }\n }\n }\n\n if (no1wkst) {\n // Check last week number of last year as\n // well. If no1wkst is 0, either the year\n // started on week start, or week number 1\n // got days from last year, so there are no\n // days from last year's last week number in\n // this year.\n let lnumweeks: number\n if (!includes(options.byweekno, -1)) {\n const lyearweekday = getWeekday(datetime(year - 1, 1, 1))\n\n let lno1wkst = pymod(7 - lyearweekday.valueOf() + options.wkst, 7)\n\n const lyearlen = isLeapYear(year - 1) ? 366 : 365\n let weekst: number\n if (lno1wkst >= 4) {\n lno1wkst = 0\n weekst = lyearlen + pymod(lyearweekday - options.wkst, 7)\n } else {\n weekst = yearlen - no1wkst\n }\n\n lnumweeks = Math.floor(52 + pymod(weekst, 7) / 4)\n } else {\n lnumweeks = -1\n }\n\n if (includes(options.byweekno, lnumweeks)) {\n for (let i = 0; i < no1wkst; i++) result.wnomask[i] = 1\n }\n }\n\n return result\n}\n\nfunction baseYearMasks(year: number) {\n const yearlen = isLeapYear(year) ? 366 : 365\n const firstyday = datetime(year, 1, 1)\n const wday = getWeekday(firstyday)\n\n if (yearlen === 365) {\n return {\n mmask: M365MASK as number[],\n mdaymask: MDAY365MASK,\n nmdaymask: NMDAY365MASK,\n wdaymask: WDAYMASK.slice(wday),\n mrange: M365RANGE,\n }\n }\n\n return {\n mmask: M366MASK as number[],\n mdaymask: MDAY366MASK,\n nmdaymask: NMDAY366MASK,\n wdaymask: WDAYMASK.slice(wday),\n mrange: M366RANGE,\n }\n}\n","import { notEmpty, repeat, range, isPresent } from '../helpers'\nimport { ParsedOptions, Frequency } from '../types'\nimport { YearInfo, rebuildYear } from './yearinfo'\nimport { rebuildMonth, MonthInfo } from './monthinfo'\nimport { easter } from './easter'\nimport { Time } from '../datetime'\nimport { datetime, sort, toOrdinal } from '../dateutil'\n\nexport type DaySet = [(number | null)[], number, number]\nexport type GetDayset = () => DaySet\n\n// =============================================================================\n// Iterinfo\n// =============================================================================\n\nexport default class Iterinfo {\n public yearinfo: YearInfo\n public monthinfo: MonthInfo\n public eastermask: number[] | null\n\n // eslint-disable-next-line no-empty-function\n constructor(private options: ParsedOptions) {}\n\n rebuild(year: number, month: number) {\n const options = this.options\n\n if (year !== this.lastyear) {\n this.yearinfo = rebuildYear(year, options)\n }\n\n if (\n notEmpty(options.bynweekday) &&\n (month !== this.lastmonth || year !== this.lastyear)\n ) {\n const { yearlen, mrange, wdaymask } = this.yearinfo\n this.monthinfo = rebuildMonth(\n year,\n month,\n yearlen,\n mrange,\n wdaymask,\n options\n )\n }\n\n if (isPresent(options.byeaster)) {\n this.eastermask = easter(year, options.byeaster)\n }\n }\n\n get lastyear() {\n return this.monthinfo ? this.monthinfo.lastyear : null\n }\n\n get lastmonth() {\n return this.monthinfo ? this.monthinfo.lastmonth : null\n }\n\n get yearlen() {\n return this.yearinfo.yearlen\n }\n\n get yearordinal() {\n return this.yearinfo.yearordinal\n }\n\n get mrange() {\n return this.yearinfo.mrange\n }\n\n get wdaymask() {\n return this.yearinfo.wdaymask\n }\n\n get mmask() {\n return this.yearinfo.mmask\n }\n\n get wnomask() {\n return this.yearinfo.wnomask\n }\n\n get nwdaymask() {\n return this.monthinfo ? this.monthinfo.nwdaymask : []\n }\n\n get nextyearlen() {\n return this.yearinfo.nextyearlen\n }\n\n get mdaymask() {\n return this.yearinfo.mdaymask\n }\n\n get nmdaymask() {\n return this.yearinfo.nmdaymask\n }\n\n ydayset() {\n return [range(this.yearlen), 0, this.yearlen]\n }\n\n mdayset(_: unknown, month: number) {\n const start = this.mrange[month - 1]\n const end = this.mrange[month]\n const set = repeat(null, this.yearlen)\n for (let i = start; i < end; i++) set[i] = i\n return [set, start, end]\n }\n\n wdayset(year: number, month: number, day: number) {\n // We need to handle cross-year weeks here.\n const set = repeat(null, this.yearlen + 7)\n let i = toOrdinal(datetime(year, month, day)) - this.yearordinal\n const start = i\n for (let j = 0; j < 7; j++) {\n set[i] = i\n ++i\n if (this.wdaymask[i] === this.options.wkst) break\n }\n return [set, start, i]\n }\n\n ddayset(year: number, month: number, day: number) {\n const set = repeat(null, this.yearlen) as (number | null)[]\n const i = toOrdinal(datetime(year, month, day)) - this.yearordinal\n set[i] = i\n return [set, i, i + 1]\n }\n\n htimeset(hour: number, _: number, second: number, millisecond: number) {\n let set: Time[] = []\n this.options.byminute.forEach((minute) => {\n set = set.concat(this.mtimeset(hour, minute, second, millisecond))\n })\n sort(set)\n return set\n }\n\n mtimeset(hour: number, minute: number, _: number, millisecond: number) {\n const set = this.options.bysecond.map(\n (second) => new Time(hour, minute, second, millisecond)\n )\n\n sort(set)\n return set\n }\n\n stimeset(hour: number, minute: number, second: number, millisecond: number) {\n return [new Time(hour, minute, second, millisecond)]\n }\n\n getdayset(freq: Frequency): (y: number, m: number, d: number) => DaySet {\n switch (freq) {\n case Frequency.YEARLY:\n return this.ydayset.bind(this)\n case Frequency.MONTHLY:\n return this.mdayset.bind(this)\n case Frequency.WEEKLY:\n return this.wdayset.bind(this)\n case Frequency.DAILY:\n return this.ddayset.bind(this)\n default:\n return this.ddayset.bind(this)\n }\n }\n\n gettimeset(\n freq: Frequency.HOURLY | Frequency.MINUTELY | Frequency.SECONDLY\n ): (h: number, m: number, s: number, ms: number) => Time[] {\n switch (freq) {\n case Frequency.HOURLY:\n return this.htimeset.bind(this)\n case Frequency.MINUTELY:\n return this.mtimeset.bind(this)\n case Frequency.SECONDLY:\n return this.stimeset.bind(this)\n }\n }\n}\n","import { ParsedOptions } from '../types'\nimport { RRule } from '../rrule'\nimport { empty, repeat, pymod } from '../helpers'\n\nexport interface MonthInfo {\n lastyear: number\n lastmonth: number\n nwdaymask: number[]\n}\n\nexport function rebuildMonth(\n year: number,\n month: number,\n yearlen: number,\n mrange: number[],\n wdaymask: number[],\n options: ParsedOptions\n) {\n const result: MonthInfo = {\n lastyear: year,\n lastmonth: month,\n nwdaymask: [],\n }\n\n let ranges: number[][] = []\n if (options.freq === RRule.YEARLY) {\n if (empty(options.bymonth)) {\n ranges = [[0, yearlen]]\n } else {\n for (let j = 0; j < options.bymonth.length; j++) {\n month = options.bymonth[j]\n ranges.push(mrange.slice(month - 1, month + 1))\n }\n }\n } else if (options.freq === RRule.MONTHLY) {\n ranges = [mrange.slice(month - 1, month + 1)]\n }\n\n if (empty(ranges)) {\n return result\n }\n\n // Weekly frequency won't get here, so we may not\n // care about cross-year weekly periods.\n result.nwdaymask = repeat(0, yearlen) as number[]\n\n for (let j = 0; j < ranges.length; j++) {\n const rang = ranges[j]\n const first = rang[0]\n const last = rang[1] - 1\n\n for (let k = 0; k < options.bynweekday.length; k++) {\n let i\n const [wday, n] = options.bynweekday[k]\n if (n < 0) {\n i = last + (n + 1) * 7\n i -= pymod(wdaymask[i] - wday, 7)\n } else {\n i = first + (n - 1) * 7\n i += pymod(7 - wdaymask[i] + wday, 7)\n }\n if (first <= i && i <= last) result.nwdaymask[i] = 1\n }\n }\n\n return result\n}\n","export function easter(y: number, offset = 0) {\n const a = y % 19\n const b = Math.floor(y / 100)\n const c = y % 100\n const d = Math.floor(b / 4)\n const e = b % 4\n const f = Math.floor((b + 8) / 25)\n const g = Math.floor((b - f + 1) / 3)\n const h = Math.floor(19 * a + b - d - g + 15) % 30\n const i = Math.floor(c / 4)\n const k = c % 4\n const l = Math.floor(32 + 2 * e + 2 * i - h - k) % 7\n const m = Math.floor((a + 11 * h + 22 * l) / 451)\n const month = Math.floor((h + l - 7 * m + 114) / 31)\n const day = ((h + l - 7 * m + 114) % 31) + 1\n const date = Date.UTC(y, month - 1, day + offset)\n const yearStart = Date.UTC(y, 0, 1)\n\n return [Math.ceil((date - yearStart) / (1000 * 60 * 60 * 24))]\n}\n","import { combine, fromOrdinal, sort } from '../dateutil'\nimport Iterinfo from '../iterinfo/index'\nimport { pymod, isPresent, includes } from '../helpers'\nimport { Time } from '../datetime'\n\nexport function buildPoslist(\n bysetpos: number[],\n timeset: Time[],\n start: number,\n end: number,\n ii: Iterinfo,\n dayset: (number | null)[]\n) {\n const poslist: Date[] = []\n\n for (let j = 0; j < bysetpos.length; j++) {\n let daypos: number\n let timepos: number\n const pos = bysetpos[j]\n\n if (pos < 0) {\n daypos = Math.floor(pos / timeset.length)\n timepos = pymod(pos, timeset.length)\n } else {\n daypos = Math.floor((pos - 1) / timeset.length)\n timepos = pymod(pos - 1, timeset.length)\n }\n\n const tmp = []\n for (let k = start; k < end; k++) {\n const val = dayset[k]\n if (!isPresent(val)) continue\n tmp.push(val)\n }\n let i: number\n if (daypos < 0) {\n i = tmp.slice(daypos)[0]\n } else {\n i = tmp[daypos]\n }\n\n const time = timeset[timepos]\n const date = fromOrdinal(ii.yearordinal + i)\n const res = combine(date, time)\n // XXX: can this ever be in the array?\n // - compare the actual date instead?\n if (!includes(poslist, res)) poslist.push(res)\n }\n\n sort(poslist)\n\n return poslist\n}\n","import IterResult from '../iterresult'\nimport { ParsedOptions, freqIsDailyOrGreater, QueryMethodTypes } from '../types'\nimport { combine, fromOrdinal, MAXYEAR } from '../dateutil'\nimport Iterinfo from '../iterinfo/index'\nimport { RRule } from '../rrule'\nimport { buildTimeset } from '../parseoptions'\nimport { notEmpty, includes, isPresent } from '../helpers'\nimport { DateWithZone } from '../datewithzone'\nimport { buildPoslist } from './poslist'\nimport { Time, DateTime } from '../datetime'\n\nexport function iter(\n iterResult: IterResult,\n options: ParsedOptions\n) {\n const { dtstart, freq, interval, until, bysetpos } = options\n\n let count = options.count\n if (count === 0 || interval === 0) {\n return emitResult(iterResult)\n }\n\n const counterDate = DateTime.fromDate(dtstart)\n\n const ii = new Iterinfo(options)\n ii.rebuild(counterDate.year, counterDate.month)\n\n let timeset = makeTimeset(ii, counterDate, options)\n\n for (;;) {\n const [dayset, start, end] = ii.getdayset(freq)(\n counterDate.year,\n counterDate.month,\n counterDate.day\n )\n\n const filtered = removeFilteredDays(dayset, start, end, ii, options)\n\n if (notEmpty(bysetpos)) {\n const poslist = buildPoslist(bysetpos, timeset, start, end, ii, dayset)\n\n for (let j = 0; j < poslist.length; j++) {\n const res = poslist[j]\n if (until && res > until) {\n return emitResult(iterResult)\n }\n\n if (res >= dtstart) {\n const rezonedDate = rezoneIfNeeded(res, options)\n if (!iterResult.accept(rezonedDate)) {\n return emitResult(iterResult)\n }\n\n if (count) {\n --count\n if (!count) {\n return emitResult(iterResult)\n }\n }\n }\n }\n } else {\n for (let j = start; j < end; j++) {\n const currentDay = dayset[j]\n if (!isPresent(currentDay)) {\n continue\n }\n\n const date = fromOrdinal(ii.yearordinal + currentDay)\n for (let k = 0; k < timeset.length; k++) {\n const time = timeset[k]\n const res = combine(date, time)\n if (until && res > until) {\n return emitResult(iterResult)\n }\n\n if (res >= dtstart) {\n const rezonedDate = rezoneIfNeeded(res, options)\n if (!iterResult.accept(rezonedDate)) {\n return emitResult(iterResult)\n }\n\n if (count) {\n --count\n if (!count) {\n return emitResult(iterResult)\n }\n }\n }\n }\n }\n }\n if (options.interval === 0) {\n return emitResult(iterResult)\n }\n\n // Handle frequency and interval\n counterDate.add(options, filtered)\n\n if (counterDate.year > MAXYEAR) {\n return emitResult(iterResult)\n }\n\n if (!freqIsDailyOrGreater(freq)) {\n timeset = ii.gettimeset(freq)(\n counterDate.hour,\n counterDate.minute,\n counterDate.second,\n 0\n )\n }\n\n ii.rebuild(counterDate.year, counterDate.month)\n }\n}\n\nfunction isFiltered(\n ii: Iterinfo,\n currentDay: number,\n options: ParsedOptions\n): boolean {\n const {\n bymonth,\n byweekno,\n byweekday,\n byeaster,\n bymonthday,\n bynmonthday,\n byyearday,\n } = options\n\n return (\n (notEmpty(bymonth) && !includes(bymonth, ii.mmask[currentDay])) ||\n (notEmpty(byweekno) && !ii.wnomask[currentDay]) ||\n (notEmpty(byweekday) && !includes(byweekday, ii.wdaymask[currentDay])) ||\n (notEmpty(ii.nwdaymask) && !ii.nwdaymask[currentDay]) ||\n (byeaster !== null && !includes(ii.eastermask, currentDay)) ||\n ((notEmpty(bymonthday) || notEmpty(bynmonthday)) &&\n !includes(bymonthday, ii.mdaymask[currentDay]) &&\n !includes(bynmonthday, ii.nmdaymask[currentDay])) ||\n (notEmpty(byyearday) &&\n ((currentDay < ii.yearlen &&\n !includes(byyearday, currentDay + 1) &&\n !includes(byyearday, -ii.yearlen + currentDay)) ||\n (currentDay >= ii.yearlen &&\n !includes(byyearday, currentDay + 1 - ii.yearlen) &&\n !includes(byyearday, -ii.nextyearlen + currentDay - ii.yearlen))))\n )\n}\n\nfunction rezoneIfNeeded(date: Date, options: ParsedOptions) {\n return new DateWithZone(date, options.tzid).rezonedDate()\n}\n\nfunction emitResult(iterResult: IterResult) {\n return iterResult.getValue()\n}\n\nfunction removeFilteredDays(\n dayset: (number | null)[],\n start: number,\n end: number,\n ii: Iterinfo,\n options: ParsedOptions\n) {\n let filtered = false\n for (let dayCounter = start; dayCounter < end; dayCounter++) {\n const currentDay = dayset[dayCounter]\n\n filtered = isFiltered(ii, currentDay, options)\n\n if (filtered) dayset[currentDay] = null\n }\n\n return filtered\n}\n\nfunction makeTimeset(\n ii: Iterinfo,\n counterDate: DateTime,\n options: ParsedOptions\n): Time[] | null {\n const { freq, byhour, byminute, bysecond } = options\n\n if (freqIsDailyOrGreater(freq)) {\n return buildTimeset(options)\n }\n\n if (\n (freq >= RRule.HOURLY &&\n notEmpty(byhour) &&\n !includes(byhour, counterDate.hour)) ||\n (freq >= RRule.MINUTELY &&\n notEmpty(byminute) &&\n !includes(byminute, counterDate.minute)) ||\n (freq >= RRule.SECONDLY &&\n notEmpty(bysecond) &&\n !includes(bysecond, counterDate.second))\n ) {\n return []\n }\n\n return ii.gettimeset(freq)(\n counterDate.hour,\n counterDate.minute,\n counterDate.second,\n counterDate.millisecond\n )\n}\n","import { isValidDate } from './dateutil'\n\nimport IterResult, { IterArgs } from './iterresult'\nimport CallbackIterResult from './callbackiterresult'\nimport { Language } from './nlp/i18n'\nimport { fromText, parseText, toText, isFullyConvertible } from './nlp/index'\nimport { DateFormatter, GetText } from './nlp/totext'\nimport {\n ParsedOptions,\n Options,\n Frequency,\n QueryMethods,\n QueryMethodTypes,\n IterResultType,\n} from './types'\nimport { parseOptions, initializeOptions } from './parseoptions'\nimport { parseString } from './parsestring'\nimport { optionsToString } from './optionstostring'\nimport { Cache, CacheKeys } from './cache'\nimport { Weekday } from './weekday'\nimport { iter } from './iter/index'\n\n// =============================================================================\n// RRule\n// =============================================================================\n\nexport const Days = {\n MO: new Weekday(0),\n TU: new Weekday(1),\n WE: new Weekday(2),\n TH: new Weekday(3),\n FR: new Weekday(4),\n SA: new Weekday(5),\n SU: new Weekday(6),\n}\n\nexport const DEFAULT_OPTIONS: Options = {\n freq: Frequency.YEARLY,\n dtstart: null,\n interval: 1,\n wkst: Days.MO,\n count: null,\n until: null,\n tzid: null,\n bysetpos: null,\n bymonth: null,\n bymonthday: null,\n bynmonthday: null,\n byyearday: null,\n byweekno: null,\n byweekday: null,\n bynweekday: null,\n byhour: null,\n byminute: null,\n bysecond: null,\n byeaster: null,\n}\n\nexport const defaultKeys = Object.keys(DEFAULT_OPTIONS) as (keyof Options)[]\n\n/**\n *\n * @param {Options?} options - see \n * - The only required option is `freq`, one of RRule.YEARLY, RRule.MONTHLY, ...\n * @constructor\n */\nexport class RRule implements QueryMethods {\n public _cache: Cache | null\n public origOptions: Partial\n public options: ParsedOptions\n\n // RRule class 'constants'\n\n static readonly FREQUENCIES: (keyof typeof Frequency)[] = [\n 'YEARLY',\n 'MONTHLY',\n 'WEEKLY',\n 'DAILY',\n 'HOURLY',\n 'MINUTELY',\n 'SECONDLY',\n ]\n\n static readonly YEARLY = Frequency.YEARLY\n static readonly MONTHLY = Frequency.MONTHLY\n static readonly WEEKLY = Frequency.WEEKLY\n static readonly DAILY = Frequency.DAILY\n static readonly HOURLY = Frequency.HOURLY\n static readonly MINUTELY = Frequency.MINUTELY\n static readonly SECONDLY = Frequency.SECONDLY\n\n static readonly MO = Days.MO\n static readonly TU = Days.TU\n static readonly WE = Days.WE\n static readonly TH = Days.TH\n static readonly FR = Days.FR\n static readonly SA = Days.SA\n static readonly SU = Days.SU\n\n constructor(options: Partial = {}, noCache = false) {\n // RFC string\n this._cache = noCache ? null : new Cache()\n\n // used by toString()\n this.origOptions = initializeOptions(options)\n const { parsedOptions } = parseOptions(options)\n this.options = parsedOptions\n }\n\n static parseText(text: string, language?: Language) {\n return parseText(text, language)\n }\n\n static fromText(text: string, language?: Language) {\n return fromText(text, language)\n }\n\n static parseString = parseString\n\n static fromString(str: string) {\n return new RRule(RRule.parseString(str) || undefined)\n }\n\n static optionsToString = optionsToString\n\n protected _iter(\n iterResult: IterResult\n ): IterResultType {\n return iter(iterResult, this.options)\n }\n\n private _cacheGet(what: CacheKeys | 'all', args?: Partial) {\n if (!this._cache) return false\n return this._cache._cacheGet(what, args)\n }\n\n public _cacheAdd(\n what: CacheKeys | 'all',\n value: Date[] | Date | null,\n args?: Partial\n ) {\n if (!this._cache) return\n return this._cache._cacheAdd(what, value, args)\n }\n\n /**\n * @param {Function} iterator - optional function that will be called\n * on each date that is added. It can return false\n * to stop the iteration.\n * @return Array containing all recurrences.\n */\n all(iterator?: (d: Date, len: number) => boolean): Date[] {\n if (iterator) {\n return this._iter(new CallbackIterResult('all', {}, iterator))\n }\n\n let result = this._cacheGet('all') as Date[] | false\n if (result === false) {\n result = this._iter(new IterResult('all', {}))\n this._cacheAdd('all', result)\n }\n return result\n }\n\n /**\n * Returns all the occurrences of the rrule between after and before.\n * The inc keyword defines what happens if after and/or before are\n * themselves occurrences. With inc == True, they will be included in the\n * list, if they are found in the recurrence set.\n *\n * @return Array\n */\n between(\n after: Date,\n before: Date,\n inc = false,\n iterator?: (d: Date, len: number) => boolean\n ): Date[] {\n if (!isValidDate(after) || !isValidDate(before)) {\n throw new Error('Invalid date passed in to RRule.between')\n }\n const args = {\n before,\n after,\n inc,\n }\n\n if (iterator) {\n return this._iter(new CallbackIterResult('between', args, iterator))\n }\n\n let result = this._cacheGet('between', args)\n if (result === false) {\n result = this._iter(new IterResult('between', args))\n this._cacheAdd('between', result, args)\n }\n return result as Date[]\n }\n\n /**\n * Returns the last recurrence before the given datetime instance.\n * The inc keyword defines what happens if dt is an occurrence.\n * With inc == True, if dt itself is an occurrence, it will be returned.\n *\n * @return Date or null\n */\n before(dt: Date, inc = false): Date | null {\n if (!isValidDate(dt)) {\n throw new Error('Invalid date passed in to RRule.before')\n }\n const args = { dt: dt, inc: inc }\n let result = this._cacheGet('before', args)\n if (result === false) {\n result = this._iter(new IterResult('before', args))\n this._cacheAdd('before', result, args)\n }\n return result as Date | null\n }\n\n /**\n * Returns the first recurrence after the given datetime instance.\n * The inc keyword defines what happens if dt is an occurrence.\n * With inc == True, if dt itself is an occurrence, it will be returned.\n *\n * @return Date or null\n */\n after(dt: Date, inc = false): Date | null {\n if (!isValidDate(dt)) {\n throw new Error('Invalid date passed in to RRule.after')\n }\n const args = { dt: dt, inc: inc }\n let result = this._cacheGet('after', args)\n if (result === false) {\n result = this._iter(new IterResult('after', args))\n this._cacheAdd('after', result, args)\n }\n return result as Date | null\n }\n\n /**\n * Returns the number of recurrences in this set. It will have go trough\n * the whole recurrence, if this hasn't been done before.\n */\n count(): number {\n return this.all().length\n }\n\n /**\n * Converts the rrule into its string representation\n *\n * @see \n * @return String\n */\n toString() {\n return optionsToString(this.origOptions)\n }\n\n /**\n * Will convert all rules described in nlp:ToText\n * to text.\n */\n toText(\n gettext?: GetText,\n language?: Language,\n dateFormatter?: DateFormatter\n ) {\n return toText(this, gettext, language, dateFormatter)\n }\n\n isFullyConvertibleToText() {\n return isFullyConvertible(this)\n }\n\n /**\n * @return a RRule instance with the same freq and options\n * as this one (cache is not cloned)\n */\n clone(): RRule {\n return new RRule(this.origOptions)\n }\n}\n","import { RRule } from './rrule'\nimport { RRuleSet } from './rruleset'\nimport { untilStringToDate } from './dateutil'\nimport { includes, split } from './helpers'\nimport { Options } from './types'\nimport { parseString, parseDtstart } from './parsestring'\n\nexport interface RRuleStrOptions {\n dtstart: Date | null\n cache: boolean\n unfold: boolean\n forceset: boolean\n compatible: boolean\n tzid: string | null\n}\n\n/**\n * RRuleStr\n * To parse a set of rrule strings\n */\nconst DEFAULT_OPTIONS: RRuleStrOptions = {\n dtstart: null,\n cache: false,\n unfold: false,\n forceset: false,\n compatible: false,\n tzid: null,\n}\n\nexport function parseInput(s: string, options: Partial) {\n const rrulevals: Partial[] = []\n let rdatevals: Date[] = []\n const exrulevals: Partial[] = []\n let exdatevals: Date[] = []\n\n const parsedDtstart = parseDtstart(s)\n const { dtstart } = parsedDtstart\n let { tzid } = parsedDtstart\n\n const lines = splitIntoLines(s, options.unfold)\n\n lines.forEach((line) => {\n if (!line) return\n const { name, parms, value } = breakDownLine(line)\n\n switch (name.toUpperCase()) {\n case 'RRULE':\n if (parms.length) {\n throw new Error(`unsupported RRULE parm: ${parms.join(',')}`)\n }\n\n rrulevals.push(parseString(line))\n break\n\n case 'RDATE':\n const [, rdateTzid] = /RDATE(?:;TZID=([^:=]+))?/i.exec(line) ?? []\n if (rdateTzid && !tzid) {\n tzid = rdateTzid\n }\n rdatevals = rdatevals.concat(parseRDate(value, parms))\n break\n\n case 'EXRULE':\n if (parms.length) {\n throw new Error(`unsupported EXRULE parm: ${parms.join(',')}`)\n }\n\n exrulevals.push(parseString(value))\n break\n\n case 'EXDATE':\n exdatevals = exdatevals.concat(parseRDate(value, parms))\n break\n\n case 'DTSTART':\n break\n\n default:\n throw new Error('unsupported property: ' + name)\n }\n })\n\n return {\n dtstart,\n tzid,\n rrulevals,\n rdatevals,\n exrulevals,\n exdatevals,\n }\n}\n\nfunction buildRule(s: string, options: Partial) {\n const { rrulevals, rdatevals, exrulevals, exdatevals, dtstart, tzid } =\n parseInput(s, options)\n\n const noCache = options.cache === false\n\n if (options.compatible) {\n options.forceset = true\n options.unfold = true\n }\n\n if (\n options.forceset ||\n rrulevals.length > 1 ||\n rdatevals.length ||\n exrulevals.length ||\n exdatevals.length\n ) {\n const rset = new RRuleSet(noCache)\n\n rset.dtstart(dtstart)\n rset.tzid(tzid || undefined)\n\n rrulevals.forEach((val) => {\n rset.rrule(new RRule(groomRruleOptions(val, dtstart, tzid), noCache))\n })\n\n rdatevals.forEach((date) => {\n rset.rdate(date)\n })\n\n exrulevals.forEach((val) => {\n rset.exrule(new RRule(groomRruleOptions(val, dtstart, tzid), noCache))\n })\n\n exdatevals.forEach((date) => {\n rset.exdate(date)\n })\n\n if (options.compatible && options.dtstart) rset.rdate(dtstart)\n return rset\n }\n\n const val = rrulevals[0] || {}\n return new RRule(\n groomRruleOptions(\n val,\n val.dtstart || options.dtstart || dtstart,\n val.tzid || options.tzid || tzid\n ),\n noCache\n )\n}\n\nexport function rrulestr(\n s: string,\n options: Partial = {}\n): RRule | RRuleSet {\n return buildRule(s, initializeOptions(options))\n}\n\nfunction groomRruleOptions(\n val: Partial,\n dtstart?: Date | null,\n tzid?: string | null\n) {\n return {\n ...val,\n dtstart,\n tzid,\n }\n}\n\nfunction initializeOptions(options: Partial) {\n const invalid: string[] = []\n const keys = Object.keys(options) as (keyof typeof options)[]\n const defaultKeys = Object.keys(\n DEFAULT_OPTIONS\n ) as (keyof typeof DEFAULT_OPTIONS)[]\n\n keys.forEach(function (key) {\n if (!includes(defaultKeys, key)) invalid.push(key)\n })\n\n if (invalid.length) {\n throw new Error('Invalid options: ' + invalid.join(', '))\n }\n\n return { ...DEFAULT_OPTIONS, ...options }\n}\n\nfunction extractName(line: string) {\n if (line.indexOf(':') === -1) {\n return {\n name: 'RRULE',\n value: line,\n }\n }\n\n const [name, value] = split(line, ':', 1)\n return {\n name,\n value,\n }\n}\n\nfunction breakDownLine(line: string) {\n const { name, value } = extractName(line)\n const parms = name.split(';')\n if (!parms) throw new Error('empty property name')\n\n return {\n name: parms[0].toUpperCase(),\n parms: parms.slice(1),\n value,\n }\n}\n\nfunction splitIntoLines(s: string, unfold = false) {\n s = s && s.trim()\n if (!s) throw new Error('Invalid empty string')\n\n // More info about 'unfold' option\n // Go head to http://www.ietf.org/rfc/rfc2445.txt\n if (!unfold) {\n return s.split(/\\s/)\n }\n\n const lines = s.split('\\n')\n let i = 0\n while (i < lines.length) {\n // TODO\n const line = (lines[i] = lines[i].replace(/\\s+$/g, ''))\n if (!line) {\n lines.splice(i, 1)\n } else if (i > 0 && line[0] === ' ') {\n lines[i - 1] += line.slice(1)\n lines.splice(i, 1)\n } else {\n i += 1\n }\n }\n\n return lines\n}\n\nfunction validateDateParm(parms: string[]) {\n parms.forEach((parm) => {\n if (!/(VALUE=DATE(-TIME)?)|(TZID=)/.test(parm)) {\n throw new Error('unsupported RDATE/EXDATE parm: ' + parm)\n }\n })\n}\n\nfunction parseRDate(rdateval: string, parms: string[]) {\n validateDateParm(parms)\n\n return rdateval.split(',').map((datestr) => untilStringToDate(datestr))\n}\n","import { RRule } from './rrule'\nimport { sort, timeToUntilString } from './dateutil'\nimport { includes } from './helpers'\nimport IterResult from './iterresult'\nimport { iterSet } from './iterset'\nimport { QueryMethodTypes, IterResultType } from './types'\nimport { rrulestr } from './rrulestr'\nimport { optionsToString } from './optionstostring'\n\nfunction createGetterSetter(fieldName: string) {\n return (field?: T) => {\n if (field !== undefined) {\n this[`_${fieldName}`] = field\n }\n\n if (this[`_${fieldName}`] !== undefined) {\n return this[`_${fieldName}`]\n }\n\n for (let i = 0; i < this._rrule.length; i++) {\n const field: T = this._rrule[i].origOptions[fieldName]\n if (field) {\n return field\n }\n }\n }\n}\n\nexport class RRuleSet extends RRule {\n public readonly _rrule: RRule[]\n public readonly _rdate: Date[]\n public readonly _exrule: RRule[]\n public readonly _exdate: Date[]\n\n private _dtstart?: Date | null | undefined\n private _tzid?: string\n\n /**\n *\n * @param {Boolean?} noCache\n * The same stratagy as RRule on cache, default to false\n * @constructor\n */\n constructor(noCache = false) {\n super({}, noCache)\n\n this._rrule = []\n this._rdate = []\n this._exrule = []\n this._exdate = []\n }\n\n dtstart = createGetterSetter.apply(this, ['dtstart'])\n tzid = createGetterSetter.apply(this, ['tzid'])\n\n _iter(\n iterResult: IterResult\n ): IterResultType {\n return iterSet(\n iterResult,\n this._rrule,\n this._exrule,\n this._rdate,\n this._exdate,\n this.tzid()\n )\n }\n\n /**\n * Adds an RRule to the set\n *\n * @param {RRule}\n */\n rrule(rrule: RRule) {\n _addRule(rrule, this._rrule)\n }\n\n /**\n * Adds an EXRULE to the set\n *\n * @param {RRule}\n */\n exrule(rrule: RRule) {\n _addRule(rrule, this._exrule)\n }\n\n /**\n * Adds an RDate to the set\n *\n * @param {Date}\n */\n rdate(date: Date) {\n _addDate(date, this._rdate)\n }\n\n /**\n * Adds an EXDATE to the set\n *\n * @param {Date}\n */\n exdate(date: Date) {\n _addDate(date, this._exdate)\n }\n\n /**\n * Get list of included rrules in this recurrence set.\n *\n * @return List of rrules\n */\n rrules() {\n return this._rrule.map((e) => rrulestr(e.toString()))\n }\n\n /**\n * Get list of excluded rrules in this recurrence set.\n *\n * @return List of exrules\n */\n exrules() {\n return this._exrule.map((e) => rrulestr(e.toString()))\n }\n\n /**\n * Get list of included datetimes in this recurrence set.\n *\n * @return List of rdates\n */\n rdates() {\n return this._rdate.map((e) => new Date(e.getTime()))\n }\n\n /**\n * Get list of included datetimes in this recurrence set.\n *\n * @return List of exdates\n */\n exdates() {\n return this._exdate.map((e) => new Date(e.getTime()))\n }\n\n valueOf() {\n let result: string[] = []\n\n if (!this._rrule.length && this._dtstart) {\n result = result.concat(optionsToString({ dtstart: this._dtstart }))\n }\n\n this._rrule.forEach(function (rrule) {\n result = result.concat(rrule.toString().split('\\n'))\n })\n\n this._exrule.forEach(function (exrule) {\n result = result.concat(\n exrule\n .toString()\n .split('\\n')\n .map((line) => line.replace(/^RRULE:/, 'EXRULE:'))\n .filter((line) => !/^DTSTART/.test(line))\n )\n })\n\n if (this._rdate.length) {\n result.push(rdatesToString('RDATE', this._rdate, this.tzid()))\n }\n\n if (this._exdate.length) {\n result.push(rdatesToString('EXDATE', this._exdate, this.tzid()))\n }\n\n return result\n }\n\n /**\n * to generate recurrence field such as:\n * DTSTART:19970902T010000Z\n * RRULE:FREQ=YEARLY;COUNT=2;BYDAY=TU\n * RRULE:FREQ=YEARLY;COUNT=1;BYDAY=TH\n */\n toString() {\n return this.valueOf().join('\\n')\n }\n\n /**\n * Create a new RRuleSet Object completely base on current instance\n */\n clone(): RRuleSet {\n const rrs = new RRuleSet(!!this._cache)\n\n this._rrule.forEach((rule) => rrs.rrule(rule.clone()))\n this._exrule.forEach((rule) => rrs.exrule(rule.clone()))\n this._rdate.forEach((date) => rrs.rdate(new Date(date.getTime())))\n this._exdate.forEach((date) => rrs.exdate(new Date(date.getTime())))\n\n return rrs\n }\n}\n\nfunction _addRule(rrule: RRule, collection: RRule[]) {\n if (!(rrule instanceof RRule)) {\n throw new TypeError(String(rrule) + ' is not RRule instance')\n }\n\n if (!includes(collection.map(String), String(rrule))) {\n collection.push(rrule)\n }\n}\n\nfunction _addDate(date: Date, collection: Date[]) {\n if (!(date instanceof Date)) {\n throw new TypeError(String(date) + ' is not Date instance')\n }\n if (!includes(collection.map(Number), Number(date))) {\n collection.push(date)\n sort(collection)\n }\n}\n\nfunction rdatesToString(\n param: string,\n rdates: Date[],\n tzid: string | undefined\n) {\n const isUTC = !tzid || tzid.toUpperCase() === 'UTC'\n const header = isUTC ? `${param}:` : `${param};TZID=${tzid}:`\n\n const dateString = rdates\n .map((rdate) => timeToUntilString(rdate.valueOf(), isUTC))\n .join(',')\n\n return `${header}${dateString}`\n}\n","import IterResult from './iterresult'\nimport { RRule } from './rrule'\nimport { DateWithZone } from './datewithzone'\nimport { iter } from './iter'\nimport { sort } from './dateutil'\nimport { QueryMethodTypes, IterResultType } from './types'\n\nexport function iterSet(\n iterResult: IterResult,\n _rrule: RRule[],\n _exrule: RRule[],\n _rdate: Date[],\n _exdate: Date[],\n tzid: string | undefined\n) {\n const _exdateHash: { [k: number]: boolean } = {}\n const _accept = iterResult.accept\n\n function evalExdate(after: Date, before: Date) {\n _exrule.forEach(function (rrule) {\n rrule.between(after, before, true).forEach(function (date) {\n _exdateHash[Number(date)] = true\n })\n })\n }\n\n _exdate.forEach(function (date) {\n const zonedDate = new DateWithZone(date, tzid).rezonedDate()\n _exdateHash[Number(zonedDate)] = true\n })\n\n iterResult.accept = function (date) {\n const dt = Number(date)\n if (isNaN(dt)) return _accept.call(this, date)\n if (!_exdateHash[dt]) {\n evalExdate(new Date(dt - 1), new Date(dt + 1))\n if (!_exdateHash[dt]) {\n _exdateHash[dt] = true\n return _accept.call(this, date)\n }\n }\n return true\n }\n\n if (iterResult.method === 'between') {\n evalExdate(iterResult.args.after, iterResult.args.before)\n iterResult.accept = function (date) {\n const dt = Number(date)\n if (!_exdateHash[dt]) {\n _exdateHash[dt] = true\n return _accept.call(this, date)\n }\n return true\n }\n }\n\n for (let i = 0; i < _rdate.length; i++) {\n const zonedDate = new DateWithZone(_rdate[i], tzid).rezonedDate()\n if (!iterResult.accept(new Date(zonedDate.getTime()))) break\n }\n\n _rrule.forEach(function (rrule) {\n iter(iterResult, rrule.options)\n })\n\n const res = iterResult._result\n sort(res)\n switch (iterResult.method) {\n case 'all':\n case 'between':\n return res as IterResultType\n case 'before':\n return ((res.length && res[res.length - 1]) || null) as IterResultType\n case 'after':\n default:\n return ((res.length && res[0]) || null) as IterResultType\n }\n}\n"],"names":["root","factory","exports","module","define","amd","self","this","__webpack_require__","definition","key","o","Object","defineProperty","enumerable","get","obj","prop","prototype","hasOwnProperty","call","Symbol","toStringTag","value","ALL_WEEKDAYS","weekday","n","Error","fromStr","str","Weekday","indexOf","nth","equals","other","toString","s","String","getJsWeekday","isPresent","isNumber","isWeekdayStr","includes","isArray","Array","range","start","end","arguments","length","rang","i","push","repeat","times","array","concat","padStart","item","targetLength","padString","slice","pymod","a","b","r","divmod","div","Math","floor","mod","empty","notEmpty","arr","val","datetime","y","m","d","h","Date","UTC","MONTH_DAYS","ONE_DAY","ORDINAL_BASE","PY_WEEKDAYS","isLeapYear","year","isDate","isValidDate","isNaN","getTime","toOrdinal","date","date2","differencems","round","fromOrdinal","ordinal","getMonthDays","month","getUTCMonth","getUTCFullYear","getWeekday","getUTCDay","monthRange","combine","time","getUTCDate","getHours","getMinutes","getSeconds","getMilliseconds","cloneDates","dates","clones","sort","timeToUntilString","utc","getUTCHours","getUTCMinutes","getUTCSeconds","join","untilStringToDate","until","bits","exec","parseInt","dateTZtoISO8601","timeZone","toLocaleString","replace","method","args","minDate","maxDate","_result","total","inc","before","after","dt","accept","tooEarly","tooLate","add","getValue","res","clone","IterResult","extendStatics","setPrototypeOf","__proto__","p","__extends","TypeError","__","constructor","create","__assign","assign","t","apply","__spreadArray","to","from","pack","ar","l","iterator","dayNames","monthNames","tokens","SKIP","number","numberAsText","every","on","at","the","first","second","third","last","for","monday","tuesday","wednesday","thursday","friday","saturday","sunday","january","february","march","april","may","june","july","august","september","october","november","december","comma","contains","defaultGetText","id","defaultDateFormatter","day","rrule","gettext","language","dateFormatter","text","options","origOptions","bymonthday","bynmonthday","byweekday","days","allWeeks","filter","someWeeks","Boolean","isWeekdays","isEveryDay","sortWeekDays","isFullyConvertible","freq","ToText","IMPLEMENTED","count","RRule","FREQUENCIES","plural","HOURLY","interval","MINUTELY","DAILY","bymonth","_bymonth","_bymonthday","_byweekday","byhour","_byhour","WEEKLY","MONTHLY","YEARLY","byyearday","list","byweekno","undefined","weekdaytext","monthtext","npos","abs","wday","callback","finalDelim","delim","realCallback","arg","delimiter","finalDelimiter","delimJoin","map","Frequency","rules","done","nextSymbol","isDone","symbol","best","bestSymbol","match","substr","name","v","acceptNumber","expect","parseText","ttr","Parser","AT","F","MO","TU","WE","TH","FR","ON","toUpperCase","wkd","decodeWKD","decodeNTH","MDAYs","decodeM","S","parse","freqIsDailyOrGreater","fromText","common","hour","minute","millisecond","fromDate","valueOf","getDay","getMonth","getYear","addYears","years","addMonths","months","yearDiv","monthMod","addWeekly","wkst","fixDay","addDaily","addHours","hours","filtered","dayDiv","hourMod","addMinutes","minutes","byminute","hourDiv","minuteMod","addSeconds","seconds","bysecond","minuteDiv","secondMod","daysinmonth","SECONDLY","Time","initializeOptions","invalid","keys","defaultKeys","parseOptions","opts","DEFAULT_OPTIONS","byeaster","dtstart","setMilliseconds","bysetpos","bynweekday","parsedOptions","parseString","rfcString","split","parseLine","x","parseDtstart","line","dtstartWithZone","tzid","header","parseRrule","forEach","attr","Days","num","parseIndividualNumber","parseNumber","optionKey","toLowerCase","parts","SyntaxError","Number","wdaypart","parseWeekday","test","RangeError","datestr","isUTC","rezonedDate","localTimeZone","Intl","DateTimeFormat","resolvedOptions","dateInLocalTZ","tzOffset","dateInTimeZone","optionsToString","outValue","buildDtstart","strValues","j","ruleString","DateWithZone","argsMatch","left","right","all","between","_cacheAdd","what","_value","_cacheGet","cached","argsKeys","findCacheDiff","cachedObject","iterResult","M365MASK","M366MASK","M28","M29","M30","M31","MDAY366MASK","MDAY365MASK","NM28","NM29","NM30","NM31","NMDAY366MASK","NMDAY365MASK","M366RANGE","M365RANGE","WDAYMASK","wdaymask","rebuildYear","firstwkst","wyearlen","firstyday","yearlen","nextyearlen","yearordinal","yearweekday","result","mmask","mdaymask","nmdaymask","mrange","baseYearMasks","wnomask","no1wkst","numweeks","k","lnumweeks","lyearweekday","lno1wkst","lyearlen","weekst","rebuild","lastyear","yearinfo","lastmonth","monthinfo","nwdaymask","ranges","rebuildMonth","eastermask","offset","c","e","f","g","yearStart","ceil","easter","ydayset","mdayset","_","set","wdayset","ddayset","htimeset","mtimeset","stimeset","getdayset","bind","gettimeset","buildPoslist","timeset","ii","dayset","poslist","daypos","timepos","pos","tmp","iter","emitResult","counterDate","DateTime","millisecondModulo","buildTimeset","makeTimeset","removeFilteredDays","rezoneIfNeeded","currentDay","isFiltered","dayCounter","SA","SU","noCache","_cache","Cache","fromString","_iter","toText","isFullyConvertibleToText","cache","unfold","forceset","compatible","parseInput","rrulevals","rdatevals","exrulevals","exdatevals","parsedDtstart","lines","trim","splice","splitIntoLines","sep","splits","extractName","parms","breakDownLine","rdateTzid","parseRDate","rrulestr","RRuleSet","groomRruleOptions","rdate","exrule","exdate","buildRule","rdateval","parm","validateDateParm","createGetterSetter","fieldName","field","_rrule","_rdate","_exrule","_exdate","_exdateHash","_accept","evalExdate","zonedDate","iterSet","_addRule","_addDate","rrules","exrules","rdates","exdates","_dtstart","rdatesToString","rrs","rule","collection","param","dateString"],"sourceRoot":""} \ No newline at end of file diff --git a/poetry.lock b/poetry.lock index ded30d3a8..fa4a31902 100644 --- a/poetry.lock +++ b/poetry.lock @@ -3881,4 +3881,4 @@ redis = ["redis"] [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "55d8df43868a30a6d3394d174e289f27030d35d1df1a52f6c5607d75d456130f" +content-hash = "33d5635b836893511bbda8076eecc5bb287ca163b917316febb82c33a4ca8738" diff --git a/pyproject.toml b/pyproject.toml index 686453270..86fa2042b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,7 +38,6 @@ django-coverage-plugin = ">=2.0.3,<4.0.0" django-filter = "^24.0" djangorestframework-guardian = "^0.3.0" uritemplate = "^4.1.1" -django-recurrence = "^1.11.1" django-oauth-toolkit = "~3.0.1" # pinned because minor versions sometimes require migrations in our models urllib3 = "^1.26.0,<2.0.0" # pinned because of uberspace issues with urllib3 2.0.0 pyyaml = "^6.0.1" @@ -49,6 +48,7 @@ requests = "^2.31.0" requests-oauthlib = "^2.0" pyjwt = "^2.8.0" scipy = "^1.12.0" +python-dateutil = "^2.9.0.post0" [tool.poetry.extras] pgsql = ["psycopg2"]