@rschedule/rschedule
Version:
A typescript library for working with recurring dates and events.
1,241 lines (1,222 loc) • 232 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = global || self, factory(global.rSchedule = {}));
}(this, function (exports) { 'use strict';
var IntersectionOperatorConfig = /** @class */ (function () {
function IntersectionOperatorConfig() {
}
return IntersectionOperatorConfig;
}());
var RuleConfig = /** @class */ (function () {
function RuleConfig() {
}
return RuleConfig;
}());
var MergeDurationOperatorConfig = /** @class */ (function () {
function MergeDurationOperatorConfig() {
}
return MergeDurationOperatorConfig;
}());
var SplitDurationOperatorConfig = /** @class */ (function () {
function SplitDurationOperatorConfig() {
}
return SplitDurationOperatorConfig;
}());
var RScheduleConfig = /** @class */ (function () {
function RScheduleConfig() {
}
RScheduleConfig.Rule = RuleConfig;
RScheduleConfig.IntersectionOperator = IntersectionOperatorConfig;
RScheduleConfig.MergeDurationOperator = MergeDurationOperatorConfig;
RScheduleConfig.SplitDurationOperator = SplitDurationOperatorConfig;
return RScheduleConfig;
}());
/*! *****************************************************************************
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of the
License at http://www.apache.org/licenses/LICENSE-2.0
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
MERCHANTABLITY OR NON-INFRINGEMENT.
See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
***************************************************************************** */
/* 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 (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
function __extends(d, b) {
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 __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 };
}
}
function __values(o) {
var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0;
if (m) return m.call(o);
return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
}
};
}
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;
}
function __spread() {
for (var ar = [], i = 0; i < arguments.length; i++)
ar = ar.concat(__read(arguments[i]));
return ar;
}
var ArgumentError = /** @class */ (function (_super) {
__extends(ArgumentError, _super);
function ArgumentError() {
return _super !== null && _super.apply(this, arguments) || this;
}
return ArgumentError;
}(Error));
var InfiniteLoopError = /** @class */ (function (_super) {
__extends(InfiniteLoopError, _super);
function InfiniteLoopError() {
return _super !== null && _super.apply(this, arguments) || this;
}
return InfiniteLoopError;
}(Error));
// Taken from https://stackoverflow.com/a/53985533/5490505
// export type TupleUnshift<A, B extends readonly [...any[]]> = ((a: A, ...r: ForcedTuple<B>) => void) extends (
// ...a: infer R
// ) => any
// ? R
// : never;
// type ForcedTuple<T> = T extends [
// infer A,
// infer B,
// infer C,
// infer D,
// infer E,
// infer F,
// infer G,
// infer H,
// infer I,
// infer J,
// infer K,
// infer L,
// infer M,
// infer N,
// infer O,
// infer P,
// infer Q,
// infer R,
// infer S,
// infer T,
// infer U,
// infer V,
// infer W,
// infer X,
// infer Y,
// infer Z
// ]
// ? [A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z]
// : T;
function numberSortComparer(a, b) {
if (a > b) {
return 1;
}
else if (b > a) {
return -1;
}
else {
return 0;
}
}
function freqToGranularity(freq) {
switch (freq) {
case 'YEARLY':
return 'year';
case 'MONTHLY':
return 'month';
case 'WEEKLY':
return 'week';
case 'DAILY':
return 'day';
case 'HOURLY':
return 'hour';
case 'MINUTELY':
return 'minute';
case 'SECONDLY':
return 'second';
default:
return 'millisecond';
}
}
function cloneJSON(json) {
return JSON.parse(JSON.stringify(json));
}
var _a;
var WEEKDAYS = [
'SU',
'MO',
'TU',
'WE',
'TH',
'FR',
'SA',
];
var MILLISECONDS_IN_SECOND = 1000;
var MILLISECONDS_IN_MINUTE = MILLISECONDS_IN_SECOND * 60;
var MILLISECONDS_IN_HOUR = MILLISECONDS_IN_MINUTE * 60;
var MILLISECONDS_IN_DAY = MILLISECONDS_IN_HOUR * 24;
var MILLISECONDS_IN_WEEK = MILLISECONDS_IN_DAY * 7;
var InvalidDateTimeError = /** @class */ (function (_super) {
__extends(InvalidDateTimeError, _super);
function InvalidDateTimeError() {
return _super !== null && _super.apply(this, arguments) || this;
}
return InvalidDateTimeError;
}(Error));
var DATETIME_ID = Symbol.for('b1231462-3560-4770-94f0-d16295d5965c');
var DateTime = /** @class */ (function () {
function DateTime(date, timezone, duration) {
/**
* This property contains an ordered array of the generator objects
* responsible for producing this DateAdapter.
*
* - If this DateAdapter was produced by a `Rule` object, this array
* will just contain the `Rule` object.
* - If this DateAdapter was produced by a `Schedule` object, this
* array will contain the `Schedule` object as well as the `Rule`
* or `Dates` object which generated it.
* - If this DateAdapter was produced by a `Calendar` object, this
* array will contain, at minimum, the `Calendar`, `Schedule`, and
* `Rule`/`Dates` objects which generated it.
*/
this.generators = [];
this[_a] = true;
this.date = new Date(date);
this.timezone = timezone || null;
this.duration = duration;
this.assertIsValid();
}
/**
* Similar to `Array.isArray()`, `isInstance()` provides a surefire method
* of determining if an object is a `DateTime` by checking against the
* global symbol registry.
*/
DateTime.isInstance = function (object) {
return !!(object && object[DATETIME_ID]);
};
DateTime.fromJSON = function (json) {
var date = new Date(Date.UTC(json.year, json.month - 1, json.day, json.hour, json.minute, json.second, json.millisecond));
return new DateTime(date, json.timezone, json.duration);
};
DateTime.fromDateAdapter = function (adapter) {
return DateTime.fromJSON(adapter.toJSON());
};
Object.defineProperty(DateTime.prototype, "end", {
/**
* Returns `undefined` if `this.duration` is falsey. Else returns
* the `end` date.
*/
get: function () {
if (!this.duration)
return;
if (this._end)
return this._end;
this._end = this.add(this.duration, 'millisecond');
return this._end;
},
enumerable: true,
configurable: true
});
// While we constrain the argument to be another DateAdapter in typescript
// we handle the case of someone passing in another type of object in javascript
DateTime.prototype.isEqual = function (object) {
if (!object) {
return false;
}
assertSameTimeZone(this, object);
return this.valueOf() === object.valueOf();
};
DateTime.prototype.isBefore = function (object) {
assertSameTimeZone(this, object);
return this.valueOf() < object.valueOf();
};
DateTime.prototype.isBeforeOrEqual = function (object) {
assertSameTimeZone(this, object);
return this.valueOf() <= object.valueOf();
};
DateTime.prototype.isAfter = function (object) {
assertSameTimeZone(this, object);
return this.valueOf() > object.valueOf();
};
DateTime.prototype.isAfterOrEqual = function (object) {
assertSameTimeZone(this, object);
return this.valueOf() >= object.valueOf();
};
DateTime.prototype.isOccurring = function (object) {
if (!this.duration) {
throw new Error('DateTime#isOccurring() is only applicable to DateTimes with durations');
}
assertSameTimeZone(this, object);
return (object.isAfterOrEqual(this) && object.isBeforeOrEqual(this.add(this.duration, 'millisecond')));
};
DateTime.prototype.add = function (amount, unit) {
switch (unit) {
case 'year':
return this.forkDateTime(addUTCYears(this.date, amount));
case 'month':
return this.forkDateTime(addUTCMonths(this.date, amount));
case 'week':
return this.forkDateTime(addUTCWeeks(this.date, amount));
case 'day':
return this.forkDateTime(addUTCDays(this.date, amount));
case 'hour':
return this.forkDateTime(addUTCHours(this.date, amount));
case 'minute':
return this.forkDateTime(addUTCMinutes(this.date, amount));
case 'second':
return this.forkDateTime(addUTCSeconds(this.date, amount));
case 'millisecond':
return this.forkDateTime(addUTCMilliseconds(this.date, amount));
default:
throw new ArgumentError('Invalid unit provided to `DateTime#add`');
}
};
DateTime.prototype.subtract = function (amount, unit) {
switch (unit) {
case 'year':
return this.forkDateTime(subUTCYears(this.date, amount));
case 'month':
return this.forkDateTime(subUTCMonths(this.date, amount));
case 'week':
return this.forkDateTime(subUTCWeeks(this.date, amount));
case 'day':
return this.forkDateTime(subUTCDays(this.date, amount));
case 'hour':
return this.forkDateTime(subUTCHours(this.date, amount));
case 'minute':
return this.forkDateTime(subUTCMinutes(this.date, amount));
case 'second':
return this.forkDateTime(subUTCSeconds(this.date, amount));
case 'millisecond':
return this.forkDateTime(subUTCMilliseconds(this.date, amount));
default:
throw new ArgumentError('Invalid unit provided to `DateTime#subtract`');
}
};
DateTime.prototype.get = function (unit) {
switch (unit) {
case 'year':
return this.date.getUTCFullYear();
case 'month':
return (this.date.getUTCMonth() + 1);
case 'yearday':
return getUTCYearDay(this.date);
case 'weekday':
return WEEKDAYS[this.date.getUTCDay()];
case 'day':
return this.date.getUTCDate();
case 'hour':
return this.date.getUTCHours();
case 'minute':
return this.date.getUTCMinutes();
case 'second':
return this.date.getUTCSeconds();
case 'millisecond':
return this.date.getUTCMilliseconds();
default:
throw new ArgumentError('Invalid unit provided to `DateTime#set`');
}
};
DateTime.prototype.set = function (unit, value) {
if (unit === 'duration') {
return new DateTime(this.date, this.timezone, value);
}
var date = new Date(this.date);
switch (unit) {
case 'year':
date.setUTCFullYear(value);
break;
case 'month': {
// If the current day of the month
// is greater than days in the month we are moving to, we need to also
// set the day to the end of that month.
var length_1 = monthLength(value, date.getUTCFullYear());
var day = date.getUTCDate();
if (day > length_1) {
date.setUTCDate(1);
date.setUTCMonth(value);
date = subUTCDays(date, 1);
}
else {
date.setUTCMonth(value - 1);
}
break;
}
case 'day':
date.setUTCDate(value);
break;
case 'hour':
date.setUTCHours(value);
break;
case 'minute':
date.setUTCMinutes(value);
break;
case 'second':
date.setUTCSeconds(value);
break;
case 'millisecond':
date.setUTCMilliseconds(value);
break;
default:
throw new ArgumentError('Invalid unit provided to `DateTime#set`');
}
return this.forkDateTime(date);
};
DateTime.prototype.granularity = function (granularity, opt) {
if (opt === void 0) { opt = {}; }
var date = this.forkDateTime(this.date);
switch (granularity) {
case 'year':
date = date.set('month', 1);
case 'month':
date = date.set('day', 1);
break;
case 'week':
date = setDateToStartOfWeek(date, opt.weekStart);
}
switch (granularity) {
case 'year':
case 'month':
case 'week':
case 'day':
date = date.set('hour', 0);
case 'hour':
date = date.set('minute', 0);
case 'minute':
date = date.set('second', 0);
case 'second':
date = date.set('millisecond', 0);
case 'millisecond':
return date;
default:
throw new ArgumentError('Invalid granularity provided to `DateTime#granularity`: ' + granularity);
}
};
DateTime.prototype.endGranularity = function (granularity, opt) {
if (opt === void 0) { opt = {}; }
var date = this.forkDateTime(this.date);
switch (granularity) {
case 'year':
date = date.set('month', 12);
case 'month':
date = date.set('day', monthLength(date.get('month'), date.get('year')));
break;
case 'week':
date = setDateToEndOfWeek(date, opt.weekStart);
}
switch (granularity) {
case 'year':
case 'month':
case 'week':
case 'day':
date = date.set('hour', 23);
case 'hour':
date = date.set('minute', 59);
case 'minute':
date = date.set('second', 59);
case 'second':
date = date.set('millisecond', 999);
case 'millisecond':
return date;
default:
throw new ArgumentError('Invalid granularity provided to `DateTime#granularity`: ' + granularity);
}
};
DateTime.prototype.toISOString = function () {
return this.date.toISOString();
};
DateTime.prototype.toDateTime = function () {
return this;
};
DateTime.prototype.toJSON = function () {
return {
timezone: this.timezone,
duration: this.duration,
year: this.get('year'),
month: this.get('month'),
day: this.get('day'),
hour: this.get('hour'),
minute: this.get('minute'),
second: this.get('second'),
millisecond: this.get('millisecond'),
};
};
DateTime.prototype.valueOf = function () {
return this.date.valueOf();
};
DateTime.prototype.assertIsValid = function () {
if (isNaN(this.valueOf())) {
throw new InvalidDateTimeError('DateTime has invalid date.');
}
return true;
};
DateTime.prototype.forkDateTime = function (date) {
return new DateTime(date, this.timezone, this.duration);
};
return DateTime;
}());
_a = DATETIME_ID;
function assertSameTimeZone(x, y) {
if (x.timezone !== y.timezone) {
throw new InvalidDateTimeError('Attempted to compare a datetime to another date in a different timezone: ' +
JSON.stringify(x) +
' and ' +
JSON.stringify(y));
}
return true;
}
function setDateToStartOfWeek(date, wkst) {
var index = orderedWeekdays(wkst).indexOf(date.get('weekday'));
return date.subtract(index, 'day');
}
function setDateToEndOfWeek(date, wkst) {
var index = orderedWeekdays(wkst).indexOf(date.get('weekday'));
return date.add(6 - index, 'day');
}
function dateTimeSortComparer(a, b) {
if (a.isAfter(b))
return 1;
if (a.isBefore(b))
return -1;
if (a.duration && b.duration) {
if (a.duration > b.duration)
return 1;
if (a.duration < b.duration)
return -1;
}
return 0;
}
function uniqDateTimes(dates) {
return Array.from(new Map(dates.map(function (date) { return [date.toISOString(), date]; })).values());
}
function orderedWeekdays(wkst) {
if (wkst === void 0) { wkst = 'SU'; }
var wkdays = WEEKDAYS.slice();
var index = wkdays.indexOf(wkst);
while (index !== 0) {
shiftArray(wkdays);
index--;
}
return wkdays;
}
function shiftArray(array, from) {
if (from === void 0) { from = 'first'; }
if (array.length === 0) {
return array;
}
else if (from === 'first') {
array.push(array.shift());
}
else {
array.unshift(array.pop());
}
return array;
}
/**
* Returns the days in the given month.
*
* @param month base-1
* @param year
*/
function monthLength(month, year) {
var block = {
1: 31,
2: getDaysInFebruary(year),
3: 31,
4: 30,
5: 31,
6: 30,
7: 31,
8: 31,
9: 30,
10: 31,
11: 30,
12: 31,
};
return block[month];
}
function getDaysInFebruary(year) {
return isLeapYear(year) ? 29 : 28;
}
// taken from date-fn
function isLeapYear(year) {
return year % 400 === 0 || (year % 4 === 0 && year % 100 !== 0);
}
function getDaysInYear(year) {
return isLeapYear(year) ? 366 : 365;
}
function getUTCYearDay(now) {
var start = new Date(Date.UTC(now.getUTCFullYear(), 0, 1));
var diff = now.valueOf() - start.valueOf();
return 1 + Math.floor(diff / MILLISECONDS_IN_DAY);
}
/**
* These functions are basically lifted from `date-fns`, but changed
* to use the UTC date methods, which `date-fns` doesn't support.
*/
function toInteger(input) {
if (input === null || input === true || input === false) {
return NaN;
}
var int = Number(input);
if (isNaN(int)) {
return int;
}
return int < 0 ? Math.ceil(int) : Math.floor(int);
}
function addMilliseconds(dirtyDate, dirtyAmount) {
if (arguments.length < 2) {
throw new TypeError('2 arguments required, but only ' + arguments.length + ' present');
}
var timestamp = dirtyDate.valueOf();
var amount = toInteger(dirtyAmount);
return new Date(timestamp + amount);
}
function addUTCYears(date, input) {
var amount = toInteger(input);
return addUTCMonths(date, amount * 12);
}
function addUTCMonths(date, input) {
var amount = toInteger(input);
date = new Date(date);
var desiredMonth = date.getUTCMonth() + amount;
var dateWithDesiredMonth = new Date(0);
dateWithDesiredMonth.setUTCFullYear(date.getUTCFullYear(), desiredMonth, 1);
dateWithDesiredMonth.setUTCHours(0, 0, 0, 0);
var daysInMonth = monthLength(dateWithDesiredMonth.getUTCMonth() + 1, dateWithDesiredMonth.getUTCFullYear());
// Set the last day of the new month
// if the original date was the last day of the longer month
date.setUTCMonth(desiredMonth, Math.min(daysInMonth, date.getUTCDate()));
return date;
}
function addUTCWeeks(date, input) {
var amount = toInteger(input);
var days = amount * 7;
return addUTCDays(date, days);
}
function addUTCDays(date, input) {
// by adding milliseconds rather than days, we supress the native Date object's automatic
// daylight savings time conversions which we don't want in UTC mode
return addUTCMilliseconds(date, toInteger(input) * MILLISECONDS_IN_DAY);
}
function addUTCHours(date, input) {
var amount = toInteger(input);
return addMilliseconds(date, amount * MILLISECONDS_IN_HOUR);
}
function addUTCMinutes(date, input) {
var amount = toInteger(input);
return addMilliseconds(date, amount * MILLISECONDS_IN_MINUTE);
}
function addUTCSeconds(date, input) {
var amount = toInteger(input);
return addMilliseconds(date, amount * MILLISECONDS_IN_SECOND);
}
function addUTCMilliseconds(date, input) {
var amount = toInteger(input);
var timestamp = date.getTime();
return new Date(timestamp + amount);
}
function subUTCYears(date, amount) {
return addUTCYears(date, -amount);
}
function subUTCMonths(date, amount) {
return addUTCMonths(date, -amount);
}
function subUTCWeeks(date, amount) {
return addUTCWeeks(date, -amount);
}
function subUTCDays(date, amount) {
return addUTCDays(date, -amount);
}
function subUTCHours(date, amount) {
return addUTCHours(date, -amount);
}
function subUTCMinutes(date, amount) {
return addUTCMinutes(date, -amount);
}
function subUTCSeconds(date, amount) {
return addUTCSeconds(date, -amount);
}
function subUTCMilliseconds(date, amount) {
return addUTCMilliseconds(date, -amount);
}
var InvalidDateAdapterError = /** @class */ (function (_super) {
__extends(InvalidDateAdapterError, _super);
function InvalidDateAdapterError() {
return _super !== null && _super.apply(this, arguments) || this;
}
return InvalidDateAdapterError;
}(Error));
var DATE_ADAPTER_ID = Symbol.for('9d2c0b75-7a72-4f24-b57f-c27e131e37b2');
var DateAdapter = /** @class */ (function () {
function DateAdapter(_date, _options) {
/**
* An array of OccurrenceGenerator objects which produced this DateAdapter.
*
* #### Details
*
* When a Rule object creates a DateAdapter, that Rule object adds itself to
* the DateAdapter's generators property before yielding the DateAdapter. If you are using a Rule
* object directly, the process ends there and the DateAdapter is yielded to you (in this case,
* generators will have the type `[Rule]`)
*
* If you are using another object, like a Schedule however, then each DateAdapter is generated
* by either a Dates (rdates) or Rule (rrule) within the Schedule. After being originally
* generated by a Dates/Rule, the DateAdapter is then filtered by any exdate/exrules and,
* assuming it passes, then the DateAdapter "bubbles up" to the Schedule object itself. At this
* point the Schedule adds itself to the generators array of the DateAdapter and yields the date
* to you. So each DateAdapter produced by a Schedule has a generators property of type
* `[Schedule, Rule | Dates]`.
*
* The generators property pairs well with the `data` property on many OccurrenceGenerators. You
* can access the OccurrenceGenerators which produced a DateAdapter via `generators`, and then
* access any arbitrary data via the `data` property.
*
* _Note: occurrence operators are never included in the generators array._
*
*/
// using `unknown[]` instead of `never[]` to support convenient generator typing in `Calendar`.
// If `never[]` is used, then `Calendar#schedules` *must* be typed as a tuple in order to
// access any values in `generators` beyond the first (Calendar) value (the rest of the values
// get typed as `never`). This would prevent passing a variable to `Calendar#schedules`.
this.generators = [];
this[_a] = true;
}
/**
* Similar to `Array.isArray()`, `isInstance()` provides a surefire method
* of determining if an object is a `DateAdapter` by checking against the
* global symbol registry.
*/
DateAdapter.isInstance = function (object) {
return !!(object && typeof object === 'object' && object[DATE_ADAPTER_ID]);
};
DateAdapter.isDate = function (_object) {
throw unimplementedError('isDate()');
};
DateAdapter.fromJSON = function (_json) {
throw unimplementedError('fromJSON()');
};
DateAdapter.fromDateTime = function (_datetime) {
throw unimplementedError('fromDateTime()');
};
Object.defineProperty(DateAdapter.prototype, "end", {
/**
* Returns `undefined` if `this.duration` is falsey. Else returns
* the `end` date.
*/
get: function () {
throw unimplementedError('end');
},
enumerable: true,
configurable: true
});
DateAdapter.prototype.set = function (_prop, _value) {
throw unimplementedError('set()');
};
DateAdapter.prototype.valueOf = function () {
throw unimplementedError('valueOf()');
};
DateAdapter.prototype.toISOString = function () {
throw unimplementedError('toISOString()');
};
DateAdapter.prototype.toDateTime = function () {
var _a;
var date = DateTime.fromJSON(this.toJSON());
(_a = date.generators).push.apply(_a, __spread(this.generators));
return date;
};
DateAdapter.prototype.toJSON = function () {
throw unimplementedError('toJSON()');
};
DateAdapter.prototype.assertIsValid = function () {
throw unimplementedError('assertIsValid()');
};
var _a;
_a = DATE_ADAPTER_ID;
DateAdapter.hasTimezoneSupport = false;
return DateAdapter;
}());
function unimplementedError(name) {
return new Error("You must implement the \"" + name + "\" method for this DateAdapter class");
}
var OccurrenceIterator = /** @class */ (function () {
function OccurrenceIterator(iterable, args) {
var _this = this;
this.iterable = iterable;
this.args = args;
this[Symbol.iterator] = function () { return _this._run(); };
this.iterator = iterable._run(args);
this.isInfinite = iterable.isInfinite;
}
OccurrenceIterator.prototype.next = function (args) {
return this._run(args).next();
};
OccurrenceIterator.prototype.toArray = function () {
if (this.args.end || this.args.take || !this.isInfinite) {
return Array.from(this._run());
}
throw new InfiniteLoopError('OccurrenceIterator#toArray() can only be called if the iterator ' +
'is not infinite, or you provide and `end` argument, or you provide ' +
'a `take` argument.');
};
OccurrenceIterator.prototype._run = function (rawArgs) {
var args, date, yieldArgs;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
args = this.normalizeRunArgs(rawArgs);
date = this.iterator.next(args).value;
_a.label = 1;
case 1:
if (!date) return [3 /*break*/, 3];
return [4 /*yield*/, this.normalizeDateOutput(date)];
case 2:
yieldArgs = _a.sent();
args = this.normalizeRunArgs(yieldArgs);
date = this.iterator.next(args).value;
return [3 /*break*/, 1];
case 3: return [2 /*return*/];
}
});
};
OccurrenceIterator.prototype.normalizeRunArgs = function (args) {
return {
skipToDate: this.normalizeDateInput(args && args.skipToDate),
};
};
OccurrenceIterator.prototype.normalizeDateInput = function (date) {
if (!date) {
return;
}
return DateAdapter.isInstance(date)
? date.set('timezone', this.iterable.timezone).toDateTime()
: new this.iterable.dateAdapter(date).set('timezone', this.iterable.timezone).toDateTime();
};
OccurrenceIterator.prototype.normalizeDateOutput = function (date) {
if (!date) {
return;
}
return this.iterable.dateAdapter.fromDateTime(date);
};
return OccurrenceIterator;
}());
var CollectionIterator = /** @class */ (function () {
function CollectionIterator(iterable, args) {
var _this = this;
this.iterable = iterable;
this.args = args;
this.granularity = 'INSTANTANIOUSLY';
this[Symbol.iterator] = function () { return _this.iterator; };
if (args.granularity) {
this.granularity = args.granularity;
}
if (args.weekStart) {
this.weekStart = args.weekStart;
}
if (args.reverse) {
throw new Error('`Calendar#collections()` does not support iterating in reverse. ' +
'Though `Calendar#occurrences()` does support iterating in reverse.');
}
// Set the end arg, if present, to the end of the period.
this.args = __assign({}, args, { start: args.start || iterable._run().next().value, end: args.end && this.getPeriod(args.end).end });
this.startDate =
(this.args.start && this.normalizeDateOutput(this.getPeriod(this.args.start).start)) || null;
this.iterator = this._run();
}
CollectionIterator.prototype.next = function () {
return this.iterator.next();
};
/**
* While `next()` and `[Symbol.iterator]` both share state,
* `toArray()` does not share state and always returns the whole
* collections array.
*/
CollectionIterator.prototype.toArray = function () {
var e_1, _a;
if (this.args.end || this.args.take || !this.iterable.isInfinite) {
var collections = [];
try {
for (var _b = __values(this._run()), _c = _b.next(); !_c.done; _c = _b.next()) {
var collection = _c.value;
collections.push(collection);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_1) throw e_1.error; }
}
return collections;
}
throw new InfiniteLoopError('CollectionIterator#toArray() can only be called if the iterator ' +
'is not infinite, or you provide and `end` argument, or you provide ' +
'a `take` argument.');
};
CollectionIterator.prototype.normalizeDateOutput = function (date) {
if (!date)
return;
return this.iterable.dateAdapter.fromDateTime(date);
};
CollectionIterator.prototype._run = function () {
var iterator, date, period, dates, index;
var _this = this;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!this.startDate)
return [2 /*return*/];
iterator = this.occurrenceIterator(this.iterable, this.args);
date = iterator.next().value;
if (!date)
return [2 /*return*/];
period = this.getPeriod(this.args.start);
dates = [];
index = 0;
_a.label = 1;
case 1:
if (!(date && (this.args.take === undefined || this.args.take > index))) return [3 /*break*/, 3];
while (date && date.isBeforeOrEqual(period.end)) {
dates.push(date);
date = iterator.next().value;
}
return [4 /*yield*/, new Collection(dates.map(function (date) { return _this.normalizeDateOutput(date); }), this.granularity, this.normalizeDateOutput(period.start), this.normalizeDateOutput(period.end))];
case 2:
_a.sent();
if (!date)
return [2 /*return*/];
dates = [];
period = this.args.incrementLinearly
? this.getPeriod(this.incrementPeriod(period.period))
: this.getPeriod(date);
// With these args, periods may overlap and the same date may show up
// in two periods. Because of this, we need to reset the iterator
// (otherwise it won't spit out a date it has already spit out).
if (this.granularity === 'MONTHLY' && this.weekStart) {
iterator = this.iterable._run({
start: period.start,
end: this.args.end,
});
date = iterator.next().value;
}
index++;
return [3 /*break*/, 1];
case 3: return [2 /*return*/];
}
});
};
CollectionIterator.prototype.getPeriod = function (date) {
var granularity = freqToGranularity(this.granularity);
var start;
var end;
var period;
if (this.granularity === 'MONTHLY' && this.weekStart) {
start = date.granularity('month').granularity('week', { weekStart: this.weekStart });
end = date.endGranularity('month').endGranularity('week', { weekStart: this.weekStart });
period = start;
}
else if (this.granularity === 'WEEKLY') {
if (!this.weekStart) {
throw new ArgumentError('"WEEKLY" granularity requires `weekStart` arg');
}
start = date.granularity('week', { weekStart: this.weekStart });
end = date.endGranularity('week', { weekStart: this.weekStart });
period = start;
}
else {
start = date.granularity(granularity);
end = date.endGranularity(granularity);
period = start;
}
return { start: start, end: end, period: period };
};
CollectionIterator.prototype.incrementPeriod = function (date) {
switch (this.granularity) {
case 'YEARLY':
return date.add(1, 'year');
case 'MONTHLY':
return date.add(1, 'month');
case 'WEEKLY':
return date.add(1, 'week');
case 'DAILY':
return date.add(1, 'day');
case 'HOURLY':
return date.add(1, 'hour');
case 'MINUTELY':
return date.add(1, 'minute');
case 'SECONDLY':
return date.add(1, 'second');
case 'INSTANTANIOUSLY':
default:
return date.add(1, 'millisecond');
}
};
CollectionIterator.prototype.occurrenceIterator = function (iterable, args) {
var start = args.start || iterable._run().next().value;
if (!start)
return iterable._run(args);
start = this.getPeriod(start).start;
return iterable._run({
start: start,
end: args.end,
});
};
return CollectionIterator;
}());
var Collection = /** @class */ (function () {
function Collection(dates, granularity, periodStart, periodEnd) {
if (dates === void 0) { dates = []; }
this.dates = dates;
this.granularity = granularity;
this.periodStart = periodStart;
this.periodEnd = periodEnd;
}
return Collection;
}());
var PipeError = /** @class */ (function (_super) {
__extends(PipeError, _super);
function PipeError() {
return _super !== null && _super.apply(this, arguments) || this;
}
return PipeError;
}(Error));
var PipeRuleBase = /** @class */ (function () {
function PipeRuleBase(args) {
this.start = args.start;
this.end = args.end;
this.options = args.options;
}
return PipeRuleBase;
}());
var PipeRule = /** @class */ (function (_super) {
__extends(PipeRule, _super);
function PipeRule() {
return _super !== null && _super.apply(this, arguments) || this;
}
PipeRule.prototype.nextValidDate = function (args, skipToDate) {
return this.nextPipe.run({
date: args.date,
invalidDate: true,
skipToDate: skipToDate,
});
};
return PipeRule;
}(PipeRuleBase));
/**
* The `FrequencyPipe` is the first pipe in the chain of rule pipes. It is
* responsible for incrementing the date, as appropriate, while taking into
* account the `RRULE` frequency and interval.
*/
var FrequencyPipe = /** @class */ (function (_super) {
__extends(FrequencyPipe, _super);
function FrequencyPipe() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.intervalUnit = freqToGranularity(_this.options.frequency);
_this.intervalStartDate = _this.normalizedStartDate(_this.start);
_this.intervalEndDate = _this.normalizedEndDate(_this.intervalStartDate);
return _this;
}
FrequencyPipe.prototype.run = function (args) {
var date = args.date;
// if a date is invalid, skipToDate will always be present
// skipToDate may also be passed by a user on an otherwise valid date
if (args.skipToDate) {
date = args.skipToDate;
this.skipToIntervalOnOrAfter(date);
if (!this.dateIsWithinInterval(date)) {
// this only applies when the interval is not 1
date = this.intervalStartDate;
}
}
else if (this.dateIsWithinInterval(date) &&
this.dateIsWithinInterval(date.add(1, 'millisecond'))) {
date = date.add(1, 'millisecond');
}
else {
this.incrementInterval(this.options.interval);
date = this.intervalStartDate;
}
return this.nextPipe.run({ date: date });
};
FrequencyPipe.prototype.normalizedStartDate = function (date) {
if (this.options.frequency === 'WEEKLY') {
return date.granularity('week', { weekStart: this.options.weekStart });
}
return date.granularity(this.intervalUnit);
};
FrequencyPipe.prototype.normalizedEndDate = function (start) {
switch (this.options.frequency) {
case 'YEARLY':
return start.add(1, 'year');
case 'MONTHLY':
return start.add(1, 'month');
case 'WEEKLY':
return start.add(1, 'week');
case 'DAILY':
return start.add(1, 'day');
case 'HOURLY':
return start.add(1, 'hour');
case 'MINUTELY':
return start.add(1, 'minute');
case 'SECONDLY':
return start.add(1, 'second');
case 'MILLISECONDLY':
return start.add(1, 'millisecond');
}
};
FrequencyPipe.prototype.incrementInterval = function (amount) {
this.intervalStartDate = this.normalizedStartDate(this.intervalStartDate.add(amount, this.intervalUnit));
this.intervalEndDate = this.normalizedEndDate(this.intervalStartDate);
};
FrequencyPipe.prototype.skipToIntervalOnOrAfter = function (date) {
this.incrementInterval(intervalDifferenceBetweenDates({
first: this.intervalStartDate,
second: date,
unit: this.intervalUnit,
interval: this.options.interval,
weekStart: this.options.weekStart,
}));
};
FrequencyPipe.prototype.dateIsWithinInterval = function (date) {
return this.intervalStartDate.isBeforeOrEqual(date) && this.intervalEndDate.isAfter(date);
};
return FrequencyPipe;
}(PipeRule));
/**
* Given the frequency (unit) and interval, this function finds
* how many jumps forward the first date needs in order to equal
* or exceed the second date.
*
* For example:
*
* 1. Unit is daily and interval is 1. The second date is 3 days
* after the first. This will return 3.
* 2. Unit is yearly and interval is 1. The second date is 3 days
* after the first. This will return 0.
* 3. Unit is yearly and interval is 3. The second date is 4 years
* after the first. This will return 6.
*/
function intervalDifferenceBetweenDates(_a) {
var first = _a.first, second = _a.second, unit = _a.unit, interval = _a.interval, weekStart = _a.weekStart;
var difference = (function () {
var intervalDuration;
switch (unit) {
case 'year':
var years = (second.get('year') - first.get('year')) * 12;
years = years + second.get('month') - first.get('month');
return Math.floor(years / 12);
case 'month':
var months = (second.get('year') - first.get('year')) * 12;
months = months + second.get('month') - first.get('month');
return months;
case 'week':
first = first.granularity('week', { weekStart: weekStart });
intervalDuration = MILLISECONDS_IN_WEEK;
break;
case 'day':
intervalDuration = MILLISECONDS_IN_DAY;
break;
case 'hour':
intervalDuration = MILLISECONDS_IN_HOUR;
break;
case 'minute':
intervalDuration = MILLISECONDS_IN_MINUTE;
break;
case 'second':
intervalDuration = MILLISECONDS_IN_SECOND;
break;
case 'millisecond':
intervalDuration = 1;
break;
default:
throw new Error('Unexpected `unit` value');
}
var diff = second.valueOf() - first.valueOf();
var sign = Math.sign(diff);
return Math.floor(Math.abs(diff) / intervalDuration) * sign;
})();
if (difference > 0 && difference < interval) {
difference = interval;
}
else if (difference > interval) {
difference = Math.ceil(difference / interval) * interval;
}
return difference;
}
var ByMonthOfYearPipe = /** @class */ (function (_super) {
__extends(ByMonthOfYearPipe, _super);
function ByMonthOfYearPipe() {
return _super !== null && _super.apply(this, arguments) || this;
}
ByMonthOfYearPipe.prototype.run = function (args) {
var e_1, _a;
if (args.invalidDate) {
return this.nextPipe.