rrule-temporal-polyfill 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +376 -0
- package/dist/chunk-XKNVKDJ3.js +2384 -0
- package/dist/index.cjs +2405 -0
- package/dist/index.d.cts +247 -0
- package/dist/index.d.ts +247 -0
- package/dist/index.js +6 -0
- package/dist/totext.cjs +3113 -0
- package/dist/totext.d.cts +6 -0
- package/dist/totext.d.ts +6 -0
- package/dist/totext.js +712 -0
- package/package.json +60 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,2405 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __defProps = Object.defineProperties;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
10
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
11
|
+
var __spreadValues = (a, b) => {
|
|
12
|
+
for (var prop in b || (b = {}))
|
|
13
|
+
if (__hasOwnProp.call(b, prop))
|
|
14
|
+
__defNormalProp(a, prop, b[prop]);
|
|
15
|
+
if (__getOwnPropSymbols)
|
|
16
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
17
|
+
if (__propIsEnum.call(b, prop))
|
|
18
|
+
__defNormalProp(a, prop, b[prop]);
|
|
19
|
+
}
|
|
20
|
+
return a;
|
|
21
|
+
};
|
|
22
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
23
|
+
var __objRest = (source, exclude) => {
|
|
24
|
+
var target = {};
|
|
25
|
+
for (var prop in source)
|
|
26
|
+
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
|
|
27
|
+
target[prop] = source[prop];
|
|
28
|
+
if (source != null && __getOwnPropSymbols)
|
|
29
|
+
for (var prop of __getOwnPropSymbols(source)) {
|
|
30
|
+
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
|
|
31
|
+
target[prop] = source[prop];
|
|
32
|
+
}
|
|
33
|
+
return target;
|
|
34
|
+
};
|
|
35
|
+
var __export = (target, all) => {
|
|
36
|
+
for (var name in all)
|
|
37
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
38
|
+
};
|
|
39
|
+
var __copyProps = (to, from, except, desc) => {
|
|
40
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
41
|
+
for (let key of __getOwnPropNames(from))
|
|
42
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
43
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
44
|
+
}
|
|
45
|
+
return to;
|
|
46
|
+
};
|
|
47
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
48
|
+
|
|
49
|
+
// src/index.ts
|
|
50
|
+
var index_exports = {};
|
|
51
|
+
__export(index_exports, {
|
|
52
|
+
RRuleTemporal: () => RRuleTemporal
|
|
53
|
+
});
|
|
54
|
+
module.exports = __toCommonJS(index_exports);
|
|
55
|
+
var import_temporal_polyfill = require("temporal-polyfill");
|
|
56
|
+
function isIcsOpts(opts) {
|
|
57
|
+
return typeof opts.rruleString === "string";
|
|
58
|
+
}
|
|
59
|
+
function unfoldLine(foldedLine) {
|
|
60
|
+
return foldedLine.replace(/\r?\n[ \t]/g, "");
|
|
61
|
+
}
|
|
62
|
+
function parseIcsDateTime(dateStr, tzid, valueType) {
|
|
63
|
+
const isDate = valueType === "DATE" || !dateStr.includes("T");
|
|
64
|
+
const isoDate = `${dateStr.slice(0, 4)}-${dateStr.slice(4, 6)}-${dateStr.slice(6, 8)}`;
|
|
65
|
+
if (isDate) {
|
|
66
|
+
return import_temporal_polyfill.Temporal.PlainDate.from(isoDate).toZonedDateTime({ timeZone: tzid });
|
|
67
|
+
}
|
|
68
|
+
if (dateStr.endsWith("Z")) {
|
|
69
|
+
const iso = `${isoDate}T${dateStr.slice(9, 15)}Z`;
|
|
70
|
+
return import_temporal_polyfill.Temporal.Instant.from(iso).toZonedDateTimeISO(tzid || "UTC");
|
|
71
|
+
} else {
|
|
72
|
+
const iso = `${isoDate}T${dateStr.slice(9)}`;
|
|
73
|
+
return import_temporal_polyfill.Temporal.PlainDateTime.from(iso).toZonedDateTime(tzid);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
function parseDateLines(lines, linePrefix, defaultTzid) {
|
|
77
|
+
const dates = [];
|
|
78
|
+
const regex = new RegExp(`^${linePrefix}(?:;VALUE=([^;]+))?(?:;TZID=([^:]+))?:(.+)`, "i");
|
|
79
|
+
for (const line of lines) {
|
|
80
|
+
const match = line.match(regex);
|
|
81
|
+
if (match) {
|
|
82
|
+
const [, valueType, tzid, dateValuesStr] = match;
|
|
83
|
+
const timezone = tzid || defaultTzid;
|
|
84
|
+
const dateValues = dateValuesStr.split(",");
|
|
85
|
+
dates.push(...dateValues.map((dateValue) => parseIcsDateTime(dateValue, timezone, valueType)));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return dates;
|
|
89
|
+
}
|
|
90
|
+
function parseNumberArray(val, sort = false) {
|
|
91
|
+
const arr = val.split(",").map((n) => parseInt(n, 10));
|
|
92
|
+
if (sort) {
|
|
93
|
+
return arr.sort((a, b) => a - b);
|
|
94
|
+
}
|
|
95
|
+
return arr;
|
|
96
|
+
}
|
|
97
|
+
function parseByMonthArray(val) {
|
|
98
|
+
return val.split(",").map((tok) => {
|
|
99
|
+
const t = tok.trim();
|
|
100
|
+
if (/^\d+L$/i.test(t)) return t.toUpperCase();
|
|
101
|
+
const n = parseInt(t, 10);
|
|
102
|
+
return Number.isFinite(n) ? n : t;
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
function parseRRuleString(input, targetTimezone, dtstart) {
|
|
106
|
+
var _a, _b, _c, _d, _e;
|
|
107
|
+
const unfoldedInput = unfoldLine(input).trim();
|
|
108
|
+
let parsedDtstart;
|
|
109
|
+
let tzid = targetTimezone;
|
|
110
|
+
let rruleLine;
|
|
111
|
+
let exDate = [];
|
|
112
|
+
let rDate = [];
|
|
113
|
+
if (/^DTSTART/im.test(unfoldedInput)) {
|
|
114
|
+
const lines = unfoldedInput.split(/\s+/);
|
|
115
|
+
const dtLine = lines.find((line) => line.match(/^DTSTART/i));
|
|
116
|
+
const rrLine = lines.find((line) => line.match(/^RRULE:/i));
|
|
117
|
+
const exLines = lines.filter((line) => line.match(/^EXDATE/i));
|
|
118
|
+
const rLines = lines.filter((line) => line.match(/^RDATE/i));
|
|
119
|
+
const dtMatch = dtLine.match(/DTSTART(?:;VALUE=([^;]+))?(?:;TZID=([^:]+))?:(.+)/i);
|
|
120
|
+
if (!dtMatch) throw new Error("Invalid DTSTART in ICS snippet");
|
|
121
|
+
const [, valueType, dtTzid, dtValue] = dtMatch;
|
|
122
|
+
const effectiveTzid = (_b = (_a = dtTzid != null ? dtTzid : targetTimezone) != null ? _a : tzid) != null ? _b : "UTC";
|
|
123
|
+
parsedDtstart = parseIcsDateTime(dtValue, effectiveTzid, valueType);
|
|
124
|
+
tzid = (_e = (_d = (_c = dtTzid != null ? dtTzid : parsedDtstart.timeZoneId) != null ? _c : targetTimezone) != null ? _d : tzid) != null ? _e : "UTC";
|
|
125
|
+
rruleLine = rrLine;
|
|
126
|
+
exDate = parseDateLines(exLines, "EXDATE", tzid != null ? tzid : "UTC");
|
|
127
|
+
rDate = parseDateLines(rLines, "RDATE", tzid != null ? tzid : "UTC");
|
|
128
|
+
} else {
|
|
129
|
+
parsedDtstart = dtstart;
|
|
130
|
+
rruleLine = unfoldedInput;
|
|
131
|
+
if (parsedDtstart) {
|
|
132
|
+
tzid = parsedDtstart.timeZoneId;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
const parts = rruleLine ? rruleLine.replace(/^RRULE:/i, "").split(";") : [];
|
|
136
|
+
const opts = {
|
|
137
|
+
dtstart: parsedDtstart,
|
|
138
|
+
tzid,
|
|
139
|
+
exDate: exDate.length > 0 ? exDate : void 0,
|
|
140
|
+
rDate: rDate.length > 0 ? rDate : void 0
|
|
141
|
+
};
|
|
142
|
+
let pendingSkip;
|
|
143
|
+
for (const part of parts) {
|
|
144
|
+
const [key, val] = part.split("=");
|
|
145
|
+
if (!key) continue;
|
|
146
|
+
switch (key.toUpperCase()) {
|
|
147
|
+
case "RSCALE":
|
|
148
|
+
if (val) {
|
|
149
|
+
opts.rscale = val.toUpperCase();
|
|
150
|
+
if (pendingSkip && !opts.skip) {
|
|
151
|
+
opts.skip = pendingSkip;
|
|
152
|
+
pendingSkip = void 0;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
break;
|
|
156
|
+
case "SKIP": {
|
|
157
|
+
const v = (val || "").toUpperCase();
|
|
158
|
+
if (!["OMIT", "BACKWARD", "FORWARD"].includes(v)) {
|
|
159
|
+
throw new Error(`Invalid SKIP value: ${val}`);
|
|
160
|
+
}
|
|
161
|
+
if (opts.rscale) {
|
|
162
|
+
opts.skip = v;
|
|
163
|
+
} else {
|
|
164
|
+
pendingSkip = v;
|
|
165
|
+
}
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
case "FREQ":
|
|
169
|
+
opts.freq = val.toUpperCase();
|
|
170
|
+
break;
|
|
171
|
+
case "INTERVAL":
|
|
172
|
+
opts.interval = parseInt(val, 10);
|
|
173
|
+
break;
|
|
174
|
+
case "COUNT":
|
|
175
|
+
opts.count = parseInt(val, 10);
|
|
176
|
+
break;
|
|
177
|
+
case "UNTIL": {
|
|
178
|
+
opts.until = parseIcsDateTime(val, tzid || "UTC");
|
|
179
|
+
if (!val.endsWith("Z") && tzid !== "UTC") {
|
|
180
|
+
throw new Error("UNTIL rule part MUST always be specified as a date with UTC time");
|
|
181
|
+
}
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
184
|
+
case "BYHOUR":
|
|
185
|
+
opts.byHour = parseNumberArray(val, true);
|
|
186
|
+
break;
|
|
187
|
+
case "BYMINUTE":
|
|
188
|
+
opts.byMinute = parseNumberArray(val, true);
|
|
189
|
+
break;
|
|
190
|
+
case "BYSECOND":
|
|
191
|
+
opts.bySecond = parseNumberArray(val, true);
|
|
192
|
+
break;
|
|
193
|
+
case "BYDAY":
|
|
194
|
+
opts.byDay = val.split(",");
|
|
195
|
+
break;
|
|
196
|
+
case "BYMONTH":
|
|
197
|
+
opts.byMonth = parseByMonthArray(val);
|
|
198
|
+
break;
|
|
199
|
+
case "BYMONTHDAY":
|
|
200
|
+
opts.byMonthDay = parseNumberArray(val);
|
|
201
|
+
break;
|
|
202
|
+
case "BYYEARDAY":
|
|
203
|
+
opts.byYearDay = parseNumberArray(val);
|
|
204
|
+
break;
|
|
205
|
+
case "BYWEEKNO":
|
|
206
|
+
opts.byWeekNo = parseNumberArray(val);
|
|
207
|
+
break;
|
|
208
|
+
case "BYSETPOS":
|
|
209
|
+
opts.bySetPos = parseNumberArray(val);
|
|
210
|
+
break;
|
|
211
|
+
case "WKST":
|
|
212
|
+
opts.wkst = val;
|
|
213
|
+
break;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
if (pendingSkip && !opts.rscale) {
|
|
217
|
+
throw new Error("SKIP MUST NOT be present unless RSCALE is present");
|
|
218
|
+
}
|
|
219
|
+
if (pendingSkip && opts.rscale && !opts.skip) {
|
|
220
|
+
opts.skip = pendingSkip;
|
|
221
|
+
}
|
|
222
|
+
return opts;
|
|
223
|
+
}
|
|
224
|
+
var _RRuleTemporal = class _RRuleTemporal {
|
|
225
|
+
constructor(params) {
|
|
226
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
227
|
+
let manual;
|
|
228
|
+
if (isIcsOpts(params)) {
|
|
229
|
+
const parsed = parseRRuleString(params.rruleString, params.tzid, params.dtstart);
|
|
230
|
+
if (!parsed.dtstart) {
|
|
231
|
+
throw new Error("dtstart is required - provide it either in rruleString or as a separate parameter");
|
|
232
|
+
}
|
|
233
|
+
this.tzid = (_b = (_a = parsed.tzid) != null ? _a : params.tzid) != null ? _b : "UTC";
|
|
234
|
+
this.originalDtstart = parsed.dtstart;
|
|
235
|
+
manual = __spreadProps(__spreadValues({}, parsed), {
|
|
236
|
+
// Allow explicit COUNT/UNTIL overrides when omitted from the RRULE string
|
|
237
|
+
count: (_c = params.count) != null ? _c : parsed.count,
|
|
238
|
+
until: (_d = params.until) != null ? _d : parsed.until,
|
|
239
|
+
maxIterations: params.maxIterations,
|
|
240
|
+
includeDtstart: params.includeDtstart,
|
|
241
|
+
tzid: this.tzid
|
|
242
|
+
});
|
|
243
|
+
} else {
|
|
244
|
+
manual = __spreadValues({}, params);
|
|
245
|
+
if (typeof manual.dtstart === "string") {
|
|
246
|
+
throw new Error("Manual dtstart must be a ZonedDateTime");
|
|
247
|
+
}
|
|
248
|
+
manual.tzid = manual.tzid || manual.dtstart.timeZoneId;
|
|
249
|
+
this.tzid = manual.tzid;
|
|
250
|
+
this.originalDtstart = manual.dtstart;
|
|
251
|
+
}
|
|
252
|
+
if (!manual.freq) throw new Error("RRULE must include FREQ");
|
|
253
|
+
manual.interval = (_e = manual.interval) != null ? _e : 1;
|
|
254
|
+
if (manual.interval <= 0) {
|
|
255
|
+
throw new Error("Cannot create RRule: interval must be greater than 0");
|
|
256
|
+
}
|
|
257
|
+
if (manual.until && !(manual.until instanceof import_temporal_polyfill.Temporal.ZonedDateTime)) {
|
|
258
|
+
throw new Error("Manual until must be a ZonedDateTime");
|
|
259
|
+
}
|
|
260
|
+
this.opts = this.sanitizeOpts(manual);
|
|
261
|
+
this.maxIterations = (_f = manual.maxIterations) != null ? _f : 1e4;
|
|
262
|
+
this.includeDtstart = (_g = manual.includeDtstart) != null ? _g : false;
|
|
263
|
+
}
|
|
264
|
+
sanitizeNumericArray(arr, min, max, allowZero = false, sort = false) {
|
|
265
|
+
if (!arr) return void 0;
|
|
266
|
+
const sanitized = arr.filter((n) => Number.isInteger(n) && n >= min && n <= max && (allowZero || n !== 0));
|
|
267
|
+
if (sanitized.length === 0) return void 0;
|
|
268
|
+
return sort ? sanitized.sort((a, b) => a - b) : sanitized;
|
|
269
|
+
}
|
|
270
|
+
sanitizeByDay(byDay) {
|
|
271
|
+
const validDay = /^([+-]?\d{1,2})?(MO|TU|WE|TH|FR|SA|SU)$/;
|
|
272
|
+
const days = (byDay != null ? byDay : []).filter((day) => day && typeof day === "string");
|
|
273
|
+
for (const day of days) {
|
|
274
|
+
const match = day.match(validDay);
|
|
275
|
+
if (!match) {
|
|
276
|
+
throw new Error(`Invalid BYDAY value: ${day}`);
|
|
277
|
+
}
|
|
278
|
+
const ord = match[1];
|
|
279
|
+
if (ord) {
|
|
280
|
+
const ordInt = parseInt(ord, 10);
|
|
281
|
+
if (ordInt === 0) {
|
|
282
|
+
throw new Error(`Invalid BYDAY value: ${day}`);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
return days.length > 0 ? days : void 0;
|
|
287
|
+
}
|
|
288
|
+
sanitizeOpts(opts) {
|
|
289
|
+
var _a;
|
|
290
|
+
opts.byDay = this.sanitizeByDay(opts.byDay);
|
|
291
|
+
if (opts.byMonth) {
|
|
292
|
+
const numeric = opts.byMonth.filter((v) => typeof v === "number");
|
|
293
|
+
const stringy = opts.byMonth.filter((v) => typeof v === "string");
|
|
294
|
+
const sanitizedNum = (_a = this.sanitizeNumericArray(numeric, 1, 12, false, false)) != null ? _a : [];
|
|
295
|
+
const merged = [...sanitizedNum, ...stringy];
|
|
296
|
+
opts.byMonth = merged.length > 0 ? merged : void 0;
|
|
297
|
+
}
|
|
298
|
+
if (opts.rscale && !opts.skip) {
|
|
299
|
+
opts.skip = "OMIT";
|
|
300
|
+
}
|
|
301
|
+
opts.byMonthDay = this.sanitizeNumericArray(opts.byMonthDay, -31, 31, false, false);
|
|
302
|
+
opts.byYearDay = this.sanitizeNumericArray(opts.byYearDay, -366, 366, false, false);
|
|
303
|
+
opts.byWeekNo = this.sanitizeNumericArray(opts.byWeekNo, -53, 53, false, false);
|
|
304
|
+
opts.byHour = this.sanitizeNumericArray(opts.byHour, 0, 23, true, true);
|
|
305
|
+
opts.byMinute = this.sanitizeNumericArray(opts.byMinute, 0, 59, true, true);
|
|
306
|
+
opts.bySecond = this.sanitizeNumericArray(opts.bySecond, 0, 59, true, true);
|
|
307
|
+
if (opts.bySetPos) {
|
|
308
|
+
if (opts.bySetPos.some((p) => p === 0)) {
|
|
309
|
+
throw new Error("bySetPos may not contain 0");
|
|
310
|
+
}
|
|
311
|
+
opts.bySetPos = this.sanitizeNumericArray(opts.bySetPos, -Infinity, Infinity, false, false);
|
|
312
|
+
}
|
|
313
|
+
return opts;
|
|
314
|
+
}
|
|
315
|
+
rawAdvance(zdt) {
|
|
316
|
+
const { freq, interval } = this.opts;
|
|
317
|
+
switch (freq) {
|
|
318
|
+
case "DAILY":
|
|
319
|
+
return zdt.add({ days: interval });
|
|
320
|
+
case "WEEKLY":
|
|
321
|
+
return zdt.add({ weeks: interval });
|
|
322
|
+
case "MONTHLY":
|
|
323
|
+
return zdt.add({ months: interval });
|
|
324
|
+
case "YEARLY":
|
|
325
|
+
return zdt.add({ years: interval });
|
|
326
|
+
case "HOURLY": {
|
|
327
|
+
const originalHour = zdt.hour;
|
|
328
|
+
let next = zdt.add({ hours: interval });
|
|
329
|
+
if (next.hour === originalHour && interval === 1) {
|
|
330
|
+
next = next.add({ hours: interval });
|
|
331
|
+
}
|
|
332
|
+
return next;
|
|
333
|
+
}
|
|
334
|
+
case "MINUTELY":
|
|
335
|
+
return zdt.add({ minutes: interval });
|
|
336
|
+
case "SECONDLY":
|
|
337
|
+
return zdt.add({ seconds: interval });
|
|
338
|
+
default:
|
|
339
|
+
throw new Error(`Unsupported FREQ: ${freq}`);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
/** Expand one base ZonedDateTime into all BYHOUR × BYMINUTE × BYSECOND
|
|
343
|
+
* combinations, keeping chronological order. If the options are not
|
|
344
|
+
* present the original date is returned unchanged.
|
|
345
|
+
*/
|
|
346
|
+
expandByTime(base) {
|
|
347
|
+
var _a, _b, _c;
|
|
348
|
+
const hours = (_a = this.opts.byHour) != null ? _a : [base.hour];
|
|
349
|
+
const minutes = (_b = this.opts.byMinute) != null ? _b : [base.minute];
|
|
350
|
+
const seconds = (_c = this.opts.bySecond) != null ? _c : [base.second];
|
|
351
|
+
const out = [];
|
|
352
|
+
for (const h of hours) {
|
|
353
|
+
for (const m of minutes) {
|
|
354
|
+
for (const s of seconds) {
|
|
355
|
+
out.push(base.with({ hour: h, minute: m, second: s }));
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
return out.sort((a, b) => import_temporal_polyfill.Temporal.ZonedDateTime.compare(a, b));
|
|
360
|
+
}
|
|
361
|
+
nextCandidateSameDate(zdt) {
|
|
362
|
+
const { freq, interval = 1, byHour, byMinute, bySecond } = this.opts;
|
|
363
|
+
if (freq === "HOURLY" && byHour && byHour.length === 1) {
|
|
364
|
+
return this.applyTimeOverride(zdt.add({ days: interval }));
|
|
365
|
+
}
|
|
366
|
+
if (freq === "MINUTELY" && byMinute && byMinute.length === 1) {
|
|
367
|
+
return this.applyTimeOverride(zdt.add({ hours: interval }));
|
|
368
|
+
}
|
|
369
|
+
if (bySecond && bySecond.length > 1) {
|
|
370
|
+
const idx = bySecond.indexOf(zdt.second);
|
|
371
|
+
if (idx !== -1 && idx < bySecond.length - 1) {
|
|
372
|
+
return zdt.with({ second: bySecond[idx + 1] });
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
if (freq === "MINUTELY" && byHour && byHour.length > 1 && !byMinute) {
|
|
376
|
+
const next = zdt.add({ minutes: interval });
|
|
377
|
+
if (byHour.includes(next.hour)) {
|
|
378
|
+
return next.with({ second: bySecond ? bySecond[0] : zdt.second });
|
|
379
|
+
}
|
|
380
|
+
const nextHour = byHour.find((h) => h > zdt.hour) || byHour[0];
|
|
381
|
+
if (nextHour && nextHour > zdt.hour) {
|
|
382
|
+
return zdt.with({ hour: nextHour, minute: 0, second: bySecond ? bySecond[0] : zdt.second });
|
|
383
|
+
}
|
|
384
|
+
return this.applyTimeOverride(zdt.add({ days: 1 }));
|
|
385
|
+
}
|
|
386
|
+
if (freq === "SECONDLY") {
|
|
387
|
+
let candidate = zdt;
|
|
388
|
+
if (bySecond && bySecond.length > 0) {
|
|
389
|
+
const nextSecondInList = bySecond.find((s) => s > candidate.second);
|
|
390
|
+
if (nextSecondInList !== void 0) {
|
|
391
|
+
return candidate.with({ second: nextSecondInList });
|
|
392
|
+
}
|
|
393
|
+
candidate = candidate.with({ second: bySecond[0] }).add({ minutes: 1 });
|
|
394
|
+
} else {
|
|
395
|
+
candidate = candidate.add({ seconds: interval });
|
|
396
|
+
}
|
|
397
|
+
if (byMinute && byMinute.length > 0) {
|
|
398
|
+
if (!byMinute.includes(candidate.minute) || candidate.minute === zdt.minute && candidate.second < zdt.second) {
|
|
399
|
+
const nextMinuteInList = byMinute.find((m) => m > candidate.minute);
|
|
400
|
+
if (nextMinuteInList !== void 0) {
|
|
401
|
+
return candidate.with({ minute: nextMinuteInList, second: bySecond ? bySecond[0] : 0 });
|
|
402
|
+
}
|
|
403
|
+
candidate = candidate.with({ minute: byMinute[0], second: bySecond ? bySecond[0] : 0 }).add({ hours: 1 });
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
if (byHour && byHour.length > 0) {
|
|
407
|
+
if (!byHour.includes(candidate.hour) || candidate.hour === zdt.hour && candidate.minute < zdt.minute) {
|
|
408
|
+
const nextHourInList = byHour.find((h) => h > candidate.hour);
|
|
409
|
+
if (nextHourInList !== void 0) {
|
|
410
|
+
return candidate.with({
|
|
411
|
+
hour: nextHourInList,
|
|
412
|
+
minute: byMinute ? byMinute[0] : 0,
|
|
413
|
+
second: bySecond ? bySecond[0] : 0
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
candidate = candidate.with({ hour: byHour[0], minute: byMinute ? byMinute[0] : 0, second: bySecond ? bySecond[0] : 0 }).add({ days: 1 });
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
return candidate;
|
|
420
|
+
}
|
|
421
|
+
if (byMinute && byMinute.length > 1) {
|
|
422
|
+
const idx = byMinute.indexOf(zdt.minute);
|
|
423
|
+
if (idx !== -1 && idx < byMinute.length - 1) {
|
|
424
|
+
return zdt.with({
|
|
425
|
+
minute: byMinute[idx + 1],
|
|
426
|
+
second: bySecond ? bySecond[0] : zdt.second
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
if (freq === "MINUTELY" && idx === byMinute.length - 1) {
|
|
430
|
+
if (byHour && byHour.length > 0) {
|
|
431
|
+
const currentHourIdx = byHour.indexOf(zdt.hour);
|
|
432
|
+
if (currentHourIdx !== -1 && currentHourIdx < byHour.length - 1) {
|
|
433
|
+
return zdt.with({
|
|
434
|
+
hour: byHour[currentHourIdx + 1],
|
|
435
|
+
minute: byMinute[0],
|
|
436
|
+
second: bySecond ? bySecond[0] : zdt.second
|
|
437
|
+
});
|
|
438
|
+
} else {
|
|
439
|
+
return this.applyTimeOverride(zdt.add({ days: 1 }));
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
return zdt.add({ hours: interval }).with({
|
|
443
|
+
minute: byMinute[0],
|
|
444
|
+
second: bySecond ? bySecond[0] : zdt.second
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
if (byHour && byHour.length > 1) {
|
|
449
|
+
const idx = byHour.indexOf(zdt.hour);
|
|
450
|
+
if (idx !== -1 && idx < byHour.length - 1) {
|
|
451
|
+
return zdt.with({
|
|
452
|
+
hour: byHour[idx + 1],
|
|
453
|
+
minute: byMinute ? byMinute[0] : zdt.minute,
|
|
454
|
+
second: bySecond ? bySecond[0] : zdt.second
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
if (freq === "HOURLY" && byHour && byHour.length > 1) {
|
|
459
|
+
return this.applyTimeOverride(zdt.add({ days: 1 }));
|
|
460
|
+
}
|
|
461
|
+
return this.applyTimeOverride(this.rawAdvance(zdt));
|
|
462
|
+
}
|
|
463
|
+
applyTimeOverride(zdt) {
|
|
464
|
+
const { byHour, byMinute, bySecond } = this.opts;
|
|
465
|
+
let dt = zdt;
|
|
466
|
+
if (byHour) dt = dt.with({ hour: byHour[0] });
|
|
467
|
+
if (byMinute) dt = dt.with({ minute: byMinute[0] });
|
|
468
|
+
if (bySecond) dt = dt.with({ second: bySecond[0] });
|
|
469
|
+
return dt;
|
|
470
|
+
}
|
|
471
|
+
computeFirst() {
|
|
472
|
+
var _a, _b, _c, _d;
|
|
473
|
+
let zdt = this.originalDtstart;
|
|
474
|
+
if (((_a = this.opts.byWeekNo) == null ? void 0 : _a.length) && ["DAILY", "HOURLY", "MINUTELY", "SECONDLY"].includes(this.opts.freq)) {
|
|
475
|
+
let targetWeek = this.opts.byWeekNo[0];
|
|
476
|
+
let targetYear = zdt.year;
|
|
477
|
+
while (targetYear <= zdt.year + 10) {
|
|
478
|
+
const jan1 = zdt.with({ year: targetYear, month: 1, day: 1 });
|
|
479
|
+
const dec31 = zdt.with({ year: targetYear, month: 12, day: 31 });
|
|
480
|
+
let hasTargetWeek = false;
|
|
481
|
+
if (targetWeek > 0) {
|
|
482
|
+
let maxWeek = 52;
|
|
483
|
+
if (jan1.dayOfWeek === 4 || dec31.dayOfWeek === 4) {
|
|
484
|
+
maxWeek = 53;
|
|
485
|
+
}
|
|
486
|
+
hasTargetWeek = targetWeek <= maxWeek;
|
|
487
|
+
} else {
|
|
488
|
+
let maxWeek = 52;
|
|
489
|
+
if (jan1.dayOfWeek === 4 || dec31.dayOfWeek === 4) {
|
|
490
|
+
maxWeek = 53;
|
|
491
|
+
}
|
|
492
|
+
hasTargetWeek = -targetWeek <= maxWeek;
|
|
493
|
+
}
|
|
494
|
+
if (hasTargetWeek) {
|
|
495
|
+
const firstThursday = jan1.add({ days: (4 - jan1.dayOfWeek + 7) % 7 });
|
|
496
|
+
let weekStart;
|
|
497
|
+
if (targetWeek > 0) {
|
|
498
|
+
weekStart = firstThursday.subtract({ days: 3 }).add({ weeks: targetWeek - 1 });
|
|
499
|
+
} else {
|
|
500
|
+
const lastWeek = jan1.dayOfWeek === 4 || dec31.dayOfWeek === 4 ? 53 : 52;
|
|
501
|
+
weekStart = firstThursday.subtract({ days: 3 }).add({ weeks: lastWeek + targetWeek });
|
|
502
|
+
}
|
|
503
|
+
if ((_b = this.opts.byDay) == null ? void 0 : _b.length) {
|
|
504
|
+
const dayMap = { MO: 1, TU: 2, WE: 3, TH: 4, FR: 5, SA: 6, SU: 7 };
|
|
505
|
+
const targetDays = this.opts.byDay.map((tok) => {
|
|
506
|
+
var _a2;
|
|
507
|
+
return (_a2 = tok.match(/(MO|TU|WE|TH|FR|SA|SU)$/)) == null ? void 0 : _a2[1];
|
|
508
|
+
}).filter(Boolean).map((day) => dayMap[day]).filter(Boolean);
|
|
509
|
+
if (targetDays.length) {
|
|
510
|
+
const candidates = targetDays.map((dayOfWeek) => {
|
|
511
|
+
const delta = (dayOfWeek - weekStart.dayOfWeek + 7) % 7;
|
|
512
|
+
return weekStart.add({ days: delta });
|
|
513
|
+
});
|
|
514
|
+
const firstCandidate = candidates.sort((a, b) => import_temporal_polyfill.Temporal.ZonedDateTime.compare(a, b))[0];
|
|
515
|
+
if (firstCandidate && import_temporal_polyfill.Temporal.ZonedDateTime.compare(firstCandidate, this.originalDtstart) >= 0) {
|
|
516
|
+
zdt = firstCandidate;
|
|
517
|
+
break;
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
} else {
|
|
521
|
+
if (import_temporal_polyfill.Temporal.ZonedDateTime.compare(weekStart, this.originalDtstart) >= 0) {
|
|
522
|
+
zdt = weekStart;
|
|
523
|
+
break;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
targetYear++;
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
if (((_c = this.opts.byDay) == null ? void 0 : _c.length) && !this.opts.byWeekNo) {
|
|
531
|
+
const dayMap = { MO: 1, TU: 2, WE: 3, TH: 4, FR: 5, SA: 6, SU: 7 };
|
|
532
|
+
const hasOrdinalTokens = this.opts.byDay.some((tok) => /^[+-]?\d/.test(tok));
|
|
533
|
+
if (hasOrdinalTokens && this.opts.byMonth && (this.opts.freq === "MINUTELY" || this.opts.freq === "SECONDLY")) {
|
|
534
|
+
const months = this.opts.byMonth.filter((v) => typeof v === "number").sort((a, b) => a - b);
|
|
535
|
+
let foundFirst = false;
|
|
536
|
+
for (let year = zdt.year; year <= zdt.year + 10 && !foundFirst; year++) {
|
|
537
|
+
for (const month of months) {
|
|
538
|
+
if (year === zdt.year && month < zdt.month) continue;
|
|
539
|
+
const monthSample = zdt.with({ year, month, day: 1 });
|
|
540
|
+
const monthlyOccs = this.generateMonthlyOccurrences(monthSample);
|
|
541
|
+
for (const occ of monthlyOccs) {
|
|
542
|
+
if (import_temporal_polyfill.Temporal.ZonedDateTime.compare(occ, zdt) >= 0) {
|
|
543
|
+
if (!occ.toPlainDate().equals(zdt.toPlainDate())) {
|
|
544
|
+
zdt = this.applyTimeOverride(occ.with({ hour: 0, minute: 0, second: 0 }));
|
|
545
|
+
} else {
|
|
546
|
+
zdt = occ;
|
|
547
|
+
}
|
|
548
|
+
foundFirst = true;
|
|
549
|
+
break;
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
if (foundFirst) break;
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
} else {
|
|
556
|
+
let deltas;
|
|
557
|
+
if (["DAILY", "HOURLY", "MINUTELY", "SECONDLY"].includes(this.opts.freq) && this.opts.byDay.every((tok) => /^[A-Z]{2}$/.test(tok))) {
|
|
558
|
+
deltas = this.opts.byDay.map((tok) => (dayMap[tok] - zdt.dayOfWeek + 7) % 7);
|
|
559
|
+
} else {
|
|
560
|
+
deltas = this.opts.byDay.map((tok) => {
|
|
561
|
+
var _a2;
|
|
562
|
+
const wdTok = (_a2 = tok.match(/(MO|TU|WE|TH|FR|SA|SU)$/)) == null ? void 0 : _a2[1];
|
|
563
|
+
return wdTok ? (dayMap[wdTok] - zdt.dayOfWeek + 7) % 7 : null;
|
|
564
|
+
}).filter((d) => d !== null);
|
|
565
|
+
}
|
|
566
|
+
if (deltas.length) {
|
|
567
|
+
zdt = zdt.add({ days: Math.min(...deltas) });
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
const { byHour, byMinute, bySecond } = this.opts;
|
|
572
|
+
if (this.opts.freq === "HOURLY" && !byHour && import_temporal_polyfill.Temporal.ZonedDateTime.compare(
|
|
573
|
+
zdt.with({ hour: 0, minute: 0, second: 0, microsecond: 0, nanosecond: 0 }),
|
|
574
|
+
this.originalDtstart
|
|
575
|
+
) > 0) {
|
|
576
|
+
zdt = zdt.with({ hour: 0, minute: 0, second: 0, microsecond: 0, nanosecond: 0 });
|
|
577
|
+
}
|
|
578
|
+
if (this.opts.freq === "MINUTELY" && !byMinute && import_temporal_polyfill.Temporal.ZonedDateTime.compare(
|
|
579
|
+
zdt.with({ hour: 0, minute: 0, second: 0, microsecond: 0, nanosecond: 0 }),
|
|
580
|
+
this.originalDtstart
|
|
581
|
+
) > 0) {
|
|
582
|
+
zdt = zdt.with({ hour: 0, minute: 0, second: 0, microsecond: 0, nanosecond: 0 });
|
|
583
|
+
}
|
|
584
|
+
if (this.opts.freq === "SECONDLY" && ((_d = this.opts.byWeekNo) == null ? void 0 : _d.length) && !bySecond && import_temporal_polyfill.Temporal.ZonedDateTime.compare(
|
|
585
|
+
zdt.with({ hour: 0, minute: 0, second: 0, microsecond: 0, nanosecond: 0 }),
|
|
586
|
+
this.originalDtstart
|
|
587
|
+
) > 0) {
|
|
588
|
+
zdt = zdt.with({ hour: 0, minute: 0, second: 0, microsecond: 0, nanosecond: 0 });
|
|
589
|
+
}
|
|
590
|
+
if (byHour || byMinute || bySecond) {
|
|
591
|
+
const candidates = this.expandByTime(zdt);
|
|
592
|
+
for (const candidate of candidates) {
|
|
593
|
+
if (import_temporal_polyfill.Temporal.ZonedDateTime.compare(candidate, this.originalDtstart) >= 0) {
|
|
594
|
+
return candidate;
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
zdt = this.applyTimeOverride(this.rawAdvance(zdt));
|
|
598
|
+
}
|
|
599
|
+
return zdt;
|
|
600
|
+
}
|
|
601
|
+
// --- NEW: constraint checks ---
|
|
602
|
+
// 2) Replace your matchesByDay with this:
|
|
603
|
+
matchesByDay(zdt) {
|
|
604
|
+
const { byDay, freq } = this.opts;
|
|
605
|
+
if (!byDay) return true;
|
|
606
|
+
const dayMap = { MO: 1, TU: 2, WE: 3, TH: 4, FR: 5, SA: 6, SU: 7 };
|
|
607
|
+
for (const token of byDay) {
|
|
608
|
+
const m = token.match(/^([+-]?\d{1,2})?(MO|TU|WE|TH|FR|SA|SU)$/);
|
|
609
|
+
if (!m) continue;
|
|
610
|
+
const ord = m[1] ? parseInt(m[1], 10) : 0;
|
|
611
|
+
const weekday = m[2];
|
|
612
|
+
if (!weekday) continue;
|
|
613
|
+
const wd = dayMap[weekday];
|
|
614
|
+
if (freq === "DAILY") {
|
|
615
|
+
if (zdt.dayOfWeek === wd) return true;
|
|
616
|
+
continue;
|
|
617
|
+
}
|
|
618
|
+
if (ord === 0) {
|
|
619
|
+
if (zdt.dayOfWeek === wd) return true;
|
|
620
|
+
continue;
|
|
621
|
+
}
|
|
622
|
+
const month = zdt.month;
|
|
623
|
+
let dt = zdt.with({ day: 1 });
|
|
624
|
+
const candidates = [];
|
|
625
|
+
while (dt.month === month) {
|
|
626
|
+
if (dt.dayOfWeek === wd) candidates.push(dt.day);
|
|
627
|
+
dt = dt.add({ days: 1 });
|
|
628
|
+
}
|
|
629
|
+
const idx = ord > 0 ? ord - 1 : candidates.length + ord;
|
|
630
|
+
if (candidates[idx] === zdt.day) return true;
|
|
631
|
+
}
|
|
632
|
+
return false;
|
|
633
|
+
}
|
|
634
|
+
matchesByMonth(zdt) {
|
|
635
|
+
const { byMonth } = this.opts;
|
|
636
|
+
if (!byMonth) return true;
|
|
637
|
+
const nums = byMonth.filter((v) => typeof v === "number");
|
|
638
|
+
if (nums.length === 0) return true;
|
|
639
|
+
return nums.includes(zdt.month);
|
|
640
|
+
}
|
|
641
|
+
matchesNumericConstraint(value, constraints, maxPositiveValue) {
|
|
642
|
+
return constraints.some((c) => {
|
|
643
|
+
const target = c > 0 ? c : maxPositiveValue + c + 1;
|
|
644
|
+
return value === target;
|
|
645
|
+
});
|
|
646
|
+
}
|
|
647
|
+
matchesByMonthDay(zdt) {
|
|
648
|
+
const { byMonthDay } = this.opts;
|
|
649
|
+
if (!byMonthDay) return true;
|
|
650
|
+
const lastDay = zdt.with({ day: 1 }).add({ months: 1 }).subtract({ days: 1 }).day;
|
|
651
|
+
return this.matchesNumericConstraint(zdt.day, byMonthDay, lastDay);
|
|
652
|
+
}
|
|
653
|
+
matchesByHour(zdt) {
|
|
654
|
+
const { byHour } = this.opts;
|
|
655
|
+
if (!byHour) return true;
|
|
656
|
+
if (byHour.includes(zdt.hour)) {
|
|
657
|
+
return true;
|
|
658
|
+
}
|
|
659
|
+
for (const h of byHour) {
|
|
660
|
+
const intendedTime = zdt.with({ hour: h });
|
|
661
|
+
if (intendedTime.hour === zdt.hour) {
|
|
662
|
+
return true;
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
return false;
|
|
666
|
+
}
|
|
667
|
+
matchesByMinute(zdt) {
|
|
668
|
+
const { byMinute } = this.opts;
|
|
669
|
+
if (!byMinute) return true;
|
|
670
|
+
return byMinute.includes(zdt.minute);
|
|
671
|
+
}
|
|
672
|
+
matchesBySecond(zdt) {
|
|
673
|
+
const { bySecond } = this.opts;
|
|
674
|
+
if (!bySecond) return true;
|
|
675
|
+
return bySecond.includes(zdt.second);
|
|
676
|
+
}
|
|
677
|
+
matchesAll(zdt) {
|
|
678
|
+
return this.matchesByMonth(zdt) && this.matchesByWeekNo(zdt) && this.matchesByYearDay(zdt) && this.matchesByMonthDay(zdt) && this.matchesByDay(zdt) && this.matchesByHour(zdt) && this.matchesByMinute(zdt) && this.matchesBySecond(zdt);
|
|
679
|
+
}
|
|
680
|
+
matchesByYearDay(zdt) {
|
|
681
|
+
const { byYearDay } = this.opts;
|
|
682
|
+
if (!byYearDay) return true;
|
|
683
|
+
const dayOfYear = zdt.dayOfYear;
|
|
684
|
+
const last = zdt.with({ month: 12, day: 31 }).dayOfYear;
|
|
685
|
+
return this.matchesNumericConstraint(dayOfYear, byYearDay, last);
|
|
686
|
+
}
|
|
687
|
+
getIsoWeekInfo(zdt) {
|
|
688
|
+
const thursday = zdt.add({ days: 4 - zdt.dayOfWeek });
|
|
689
|
+
const year = thursday.year;
|
|
690
|
+
const jan1 = zdt.with({ year, month: 1, day: 1 });
|
|
691
|
+
const firstThursday = jan1.add({ days: (4 - jan1.dayOfWeek + 7) % 7 });
|
|
692
|
+
const diffDays = thursday.toPlainDate().since(firstThursday.toPlainDate()).days;
|
|
693
|
+
const week = Math.floor(diffDays / 7) + 1;
|
|
694
|
+
return { week, year };
|
|
695
|
+
}
|
|
696
|
+
matchesByWeekNo(zdt) {
|
|
697
|
+
const { byWeekNo } = this.opts;
|
|
698
|
+
if (!byWeekNo) return true;
|
|
699
|
+
const { week, year } = this.getIsoWeekInfo(zdt);
|
|
700
|
+
const jan1 = zdt.with({ year, month: 1, day: 1 });
|
|
701
|
+
const isLeapYear = jan1.inLeapYear;
|
|
702
|
+
const lastWeek = jan1.dayOfWeek === 4 || isLeapYear && jan1.dayOfWeek === 3 ? 53 : 52;
|
|
703
|
+
return byWeekNo.some((wn) => {
|
|
704
|
+
if (wn > 0) {
|
|
705
|
+
return week === wn;
|
|
706
|
+
} else {
|
|
707
|
+
return week === lastWeek + wn + 1;
|
|
708
|
+
}
|
|
709
|
+
});
|
|
710
|
+
}
|
|
711
|
+
options() {
|
|
712
|
+
return this.opts;
|
|
713
|
+
}
|
|
714
|
+
cloneOptions() {
|
|
715
|
+
const _a = this.opts, {
|
|
716
|
+
byHour,
|
|
717
|
+
byMinute,
|
|
718
|
+
bySecond,
|
|
719
|
+
byDay,
|
|
720
|
+
byMonth,
|
|
721
|
+
byMonthDay,
|
|
722
|
+
byYearDay,
|
|
723
|
+
byWeekNo,
|
|
724
|
+
bySetPos,
|
|
725
|
+
rDate,
|
|
726
|
+
exDate
|
|
727
|
+
} = _a, rest = __objRest(_a, [
|
|
728
|
+
"byHour",
|
|
729
|
+
"byMinute",
|
|
730
|
+
"bySecond",
|
|
731
|
+
"byDay",
|
|
732
|
+
"byMonth",
|
|
733
|
+
"byMonthDay",
|
|
734
|
+
"byYearDay",
|
|
735
|
+
"byWeekNo",
|
|
736
|
+
"bySetPos",
|
|
737
|
+
"rDate",
|
|
738
|
+
"exDate"
|
|
739
|
+
]);
|
|
740
|
+
return __spreadProps(__spreadValues({}, rest), {
|
|
741
|
+
byHour: byHour ? [...byHour] : void 0,
|
|
742
|
+
byMinute: byMinute ? [...byMinute] : void 0,
|
|
743
|
+
bySecond: bySecond ? [...bySecond] : void 0,
|
|
744
|
+
byDay: byDay ? [...byDay] : void 0,
|
|
745
|
+
byMonth: byMonth ? [...byMonth] : void 0,
|
|
746
|
+
byMonthDay: byMonthDay ? [...byMonthDay] : void 0,
|
|
747
|
+
byYearDay: byYearDay ? [...byYearDay] : void 0,
|
|
748
|
+
byWeekNo: byWeekNo ? [...byWeekNo] : void 0,
|
|
749
|
+
bySetPos: bySetPos ? [...bySetPos] : void 0,
|
|
750
|
+
rDate: rDate ? [...rDate] : void 0,
|
|
751
|
+
exDate: exDate ? [...exDate] : void 0
|
|
752
|
+
});
|
|
753
|
+
}
|
|
754
|
+
cloneUpdateOptions(updates) {
|
|
755
|
+
const cloned = {};
|
|
756
|
+
if (Object.prototype.hasOwnProperty.call(updates, "byHour")) {
|
|
757
|
+
cloned.byHour = Array.isArray(updates.byHour) ? [...updates.byHour] : updates.byHour;
|
|
758
|
+
}
|
|
759
|
+
if (Object.prototype.hasOwnProperty.call(updates, "byMinute")) {
|
|
760
|
+
cloned.byMinute = Array.isArray(updates.byMinute) ? [...updates.byMinute] : updates.byMinute;
|
|
761
|
+
}
|
|
762
|
+
if (Object.prototype.hasOwnProperty.call(updates, "bySecond")) {
|
|
763
|
+
cloned.bySecond = Array.isArray(updates.bySecond) ? [...updates.bySecond] : updates.bySecond;
|
|
764
|
+
}
|
|
765
|
+
if (Object.prototype.hasOwnProperty.call(updates, "byDay")) {
|
|
766
|
+
cloned.byDay = Array.isArray(updates.byDay) ? [...updates.byDay] : updates.byDay;
|
|
767
|
+
}
|
|
768
|
+
if (Object.prototype.hasOwnProperty.call(updates, "byMonth")) {
|
|
769
|
+
cloned.byMonth = Array.isArray(updates.byMonth) ? [...updates.byMonth] : updates.byMonth;
|
|
770
|
+
}
|
|
771
|
+
if (Object.prototype.hasOwnProperty.call(updates, "byMonthDay")) {
|
|
772
|
+
cloned.byMonthDay = Array.isArray(updates.byMonthDay) ? [...updates.byMonthDay] : updates.byMonthDay;
|
|
773
|
+
}
|
|
774
|
+
if (Object.prototype.hasOwnProperty.call(updates, "byYearDay")) {
|
|
775
|
+
cloned.byYearDay = Array.isArray(updates.byYearDay) ? [...updates.byYearDay] : updates.byYearDay;
|
|
776
|
+
}
|
|
777
|
+
if (Object.prototype.hasOwnProperty.call(updates, "byWeekNo")) {
|
|
778
|
+
cloned.byWeekNo = Array.isArray(updates.byWeekNo) ? [...updates.byWeekNo] : updates.byWeekNo;
|
|
779
|
+
}
|
|
780
|
+
if (Object.prototype.hasOwnProperty.call(updates, "bySetPos")) {
|
|
781
|
+
cloned.bySetPos = Array.isArray(updates.bySetPos) ? [...updates.bySetPos] : updates.bySetPos;
|
|
782
|
+
}
|
|
783
|
+
if (Object.prototype.hasOwnProperty.call(updates, "rDate")) {
|
|
784
|
+
cloned.rDate = Array.isArray(updates.rDate) ? [...updates.rDate] : updates.rDate;
|
|
785
|
+
}
|
|
786
|
+
if (Object.prototype.hasOwnProperty.call(updates, "exDate")) {
|
|
787
|
+
cloned.exDate = Array.isArray(updates.exDate) ? [...updates.exDate] : updates.exDate;
|
|
788
|
+
}
|
|
789
|
+
return cloned;
|
|
790
|
+
}
|
|
791
|
+
/**
|
|
792
|
+
* Create a new {@link RRuleTemporal} instance with modified options while keeping the current one unchanged.
|
|
793
|
+
*
|
|
794
|
+
* @example
|
|
795
|
+
* ```ts
|
|
796
|
+
* const updated = rule.with({byMonthDay: [3]});
|
|
797
|
+
* ```
|
|
798
|
+
*/
|
|
799
|
+
with(updates) {
|
|
800
|
+
var _a, _b;
|
|
801
|
+
const merged = __spreadProps(__spreadValues(__spreadValues(__spreadValues({}, this.cloneOptions()), updates), this.cloneUpdateOptions(updates)), {
|
|
802
|
+
tzid: (_a = updates.tzid) != null ? _a : this.opts.tzid,
|
|
803
|
+
dtstart: (_b = updates.dtstart) != null ? _b : this.opts.dtstart
|
|
804
|
+
});
|
|
805
|
+
return new _RRuleTemporal(merged);
|
|
806
|
+
}
|
|
807
|
+
addDtstartIfNeeded(dates, iterator) {
|
|
808
|
+
if (this.includeDtstart && !this.matchesAll(this.originalDtstart)) {
|
|
809
|
+
if (iterator && this.isExcluded(this.originalDtstart)) {
|
|
810
|
+
return true;
|
|
811
|
+
}
|
|
812
|
+
if (iterator && !iterator(this.originalDtstart, dates.length)) {
|
|
813
|
+
return false;
|
|
814
|
+
}
|
|
815
|
+
dates.push(this.originalDtstart);
|
|
816
|
+
if (this.shouldBreakForCountLimit(dates.length)) {
|
|
817
|
+
return false;
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
return true;
|
|
821
|
+
}
|
|
822
|
+
processOccurrences(occs, dates, start, iterator, extraFilters) {
|
|
823
|
+
let shouldBreak = false;
|
|
824
|
+
for (const occ of occs) {
|
|
825
|
+
if (import_temporal_polyfill.Temporal.ZonedDateTime.compare(occ, start) < 0) continue;
|
|
826
|
+
if (this.opts.until && import_temporal_polyfill.Temporal.ZonedDateTime.compare(occ, this.opts.until) > 0) {
|
|
827
|
+
shouldBreak = true;
|
|
828
|
+
break;
|
|
829
|
+
}
|
|
830
|
+
if (extraFilters && !extraFilters(occ)) {
|
|
831
|
+
continue;
|
|
832
|
+
}
|
|
833
|
+
if (iterator && this.isExcluded(occ)) {
|
|
834
|
+
continue;
|
|
835
|
+
}
|
|
836
|
+
if (iterator && !iterator(occ, dates.length)) {
|
|
837
|
+
shouldBreak = true;
|
|
838
|
+
break;
|
|
839
|
+
}
|
|
840
|
+
dates.push(occ);
|
|
841
|
+
if (this.shouldBreakForCountLimit(dates.length)) {
|
|
842
|
+
shouldBreak = true;
|
|
843
|
+
break;
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
return { shouldBreak };
|
|
847
|
+
}
|
|
848
|
+
/**
|
|
849
|
+
* Returns all occurrences of the rule.
|
|
850
|
+
* @param iterator - An optional callback iterator function that can be used to filter or modify the occurrences.
|
|
851
|
+
* @returns An array of Temporal.ZonedDateTime objects representing all occurrences of the rule.
|
|
852
|
+
*/
|
|
853
|
+
_allMonthlyByDayOrMonthDay(iterator) {
|
|
854
|
+
const dates = [];
|
|
855
|
+
let iterationCount = 0;
|
|
856
|
+
const start = this.originalDtstart;
|
|
857
|
+
if (!this.addDtstartIfNeeded(dates, iterator)) {
|
|
858
|
+
return this.applyCountLimitAndMergeRDates(dates, iterator);
|
|
859
|
+
}
|
|
860
|
+
let monthCursor = start.with({ day: 1 });
|
|
861
|
+
while (true) {
|
|
862
|
+
if (++iterationCount > this.maxIterations) {
|
|
863
|
+
throw new Error(`Maximum iterations (${this.maxIterations}) exceeded in all()`);
|
|
864
|
+
}
|
|
865
|
+
let occs = this.generateMonthlyOccurrences(monthCursor);
|
|
866
|
+
occs = this.applyBySetPos(occs);
|
|
867
|
+
if (monthCursor.month === start.month && occs.some((o) => import_temporal_polyfill.Temporal.ZonedDateTime.compare(o, start) < 0) && occs.some((o) => import_temporal_polyfill.Temporal.ZonedDateTime.compare(o, start) === 0)) {
|
|
868
|
+
monthCursor = monthCursor.add({ months: this.opts.interval });
|
|
869
|
+
continue;
|
|
870
|
+
}
|
|
871
|
+
const { shouldBreak } = this.processOccurrences(occs, dates, start, iterator);
|
|
872
|
+
if (shouldBreak) {
|
|
873
|
+
break;
|
|
874
|
+
}
|
|
875
|
+
monthCursor = monthCursor.add({ months: this.opts.interval });
|
|
876
|
+
}
|
|
877
|
+
return this.applyCountLimitAndMergeRDates(dates, iterator);
|
|
878
|
+
}
|
|
879
|
+
_allWeekly(iterator) {
|
|
880
|
+
var _a;
|
|
881
|
+
const dates = [];
|
|
882
|
+
let iterationCount = 0;
|
|
883
|
+
const start = this.originalDtstart;
|
|
884
|
+
if (!this.addDtstartIfNeeded(dates, iterator)) {
|
|
885
|
+
return this.applyCountLimitAndMergeRDates(dates, iterator);
|
|
886
|
+
}
|
|
887
|
+
const dayMap = { MO: 1, TU: 2, WE: 3, TH: 4, FR: 5, SA: 6, SU: 7 };
|
|
888
|
+
const tokens = this.opts.byDay ? [...this.opts.byDay] : this.opts.byMonthDay && this.opts.byMonthDay.length > 0 ? Object.keys(dayMap) : [Object.entries(dayMap).find(([, d]) => d === start.dayOfWeek)[0]];
|
|
889
|
+
const dows = tokens.map((tok) => dayMap[tok.slice(-2)]).filter((d) => d !== void 0).sort((a, b) => a - b);
|
|
890
|
+
const firstWeekDates = dows.map((dw) => {
|
|
891
|
+
const delta = (dw - start.dayOfWeek + 7) % 7;
|
|
892
|
+
return start.add({ days: delta });
|
|
893
|
+
});
|
|
894
|
+
const firstOccurrence = firstWeekDates.reduce((a, b) => import_temporal_polyfill.Temporal.ZonedDateTime.compare(a, b) <= 0 ? a : b);
|
|
895
|
+
const wkstDay = (_a = dayMap[this.opts.wkst || "MO"]) != null ? _a : 1;
|
|
896
|
+
const firstOccWeekOffset = (firstOccurrence.dayOfWeek - wkstDay + 7) % 7;
|
|
897
|
+
let weekCursor = firstOccurrence.subtract({ days: firstOccWeekOffset });
|
|
898
|
+
while (true) {
|
|
899
|
+
if (++iterationCount > this.maxIterations) {
|
|
900
|
+
throw new Error(`Maximum iterations (${this.maxIterations}) exceeded in all()`);
|
|
901
|
+
}
|
|
902
|
+
let occs = dows.flatMap((dw) => {
|
|
903
|
+
const delta = (dw - wkstDay + 7) % 7;
|
|
904
|
+
const sameDate = weekCursor.add({ days: delta });
|
|
905
|
+
return this.expandByTime(sameDate);
|
|
906
|
+
}).sort((a, b) => import_temporal_polyfill.Temporal.ZonedDateTime.compare(a, b));
|
|
907
|
+
occs = this.applyBySetPos(occs);
|
|
908
|
+
const { shouldBreak } = this.processOccurrences(
|
|
909
|
+
occs,
|
|
910
|
+
dates,
|
|
911
|
+
start,
|
|
912
|
+
iterator,
|
|
913
|
+
(occ) => this.matchesByMonth(occ) && this.matchesByMonthDay(occ)
|
|
914
|
+
);
|
|
915
|
+
if (shouldBreak) {
|
|
916
|
+
break;
|
|
917
|
+
}
|
|
918
|
+
weekCursor = weekCursor.add({ weeks: this.opts.interval });
|
|
919
|
+
}
|
|
920
|
+
return this.applyCountLimitAndMergeRDates(dates, iterator);
|
|
921
|
+
}
|
|
922
|
+
_allMonthlyByMonth(iterator) {
|
|
923
|
+
const dates = [];
|
|
924
|
+
let iterationCount = 0;
|
|
925
|
+
const start = this.originalDtstart;
|
|
926
|
+
if (!this.addDtstartIfNeeded(dates, iterator)) {
|
|
927
|
+
return this.applyCountLimitAndMergeRDates(dates, iterator);
|
|
928
|
+
}
|
|
929
|
+
const months = this.opts.byMonth.filter((v) => typeof v === "number").sort((a, b) => a - b);
|
|
930
|
+
let monthOffset = 0;
|
|
931
|
+
let startMonthIndex = months.findIndex((m) => m >= start.month);
|
|
932
|
+
if (startMonthIndex === -1) {
|
|
933
|
+
startMonthIndex = 0;
|
|
934
|
+
monthOffset = 1;
|
|
935
|
+
}
|
|
936
|
+
while (true) {
|
|
937
|
+
if (++iterationCount > this.maxIterations) {
|
|
938
|
+
throw new Error(`Maximum iterations (${this.maxIterations}) exceeded in all()`);
|
|
939
|
+
}
|
|
940
|
+
const monthIndex = startMonthIndex + monthOffset;
|
|
941
|
+
const targetMonth = months[monthIndex % months.length];
|
|
942
|
+
const yearsToAdd = Math.floor(monthIndex / months.length);
|
|
943
|
+
const candidate = start.with({
|
|
944
|
+
year: start.year + yearsToAdd,
|
|
945
|
+
month: targetMonth
|
|
946
|
+
});
|
|
947
|
+
if (this.opts.until && import_temporal_polyfill.Temporal.ZonedDateTime.compare(candidate, this.opts.until) > 0) {
|
|
948
|
+
break;
|
|
949
|
+
}
|
|
950
|
+
if (import_temporal_polyfill.Temporal.ZonedDateTime.compare(candidate, start) >= 0) {
|
|
951
|
+
if (iterator && this.isExcluded(candidate)) {
|
|
952
|
+
continue;
|
|
953
|
+
}
|
|
954
|
+
if (iterator && !iterator(candidate, dates.length)) {
|
|
955
|
+
break;
|
|
956
|
+
}
|
|
957
|
+
dates.push(candidate);
|
|
958
|
+
if (this.shouldBreakForCountLimit(dates.length)) {
|
|
959
|
+
break;
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
monthOffset++;
|
|
963
|
+
}
|
|
964
|
+
return this.applyCountLimitAndMergeRDates(dates, iterator);
|
|
965
|
+
}
|
|
966
|
+
_allYearlyByMonth(iterator) {
|
|
967
|
+
const dates = [];
|
|
968
|
+
let iterationCount = 0;
|
|
969
|
+
const start = this.originalDtstart;
|
|
970
|
+
if (!this.addDtstartIfNeeded(dates, iterator)) {
|
|
971
|
+
return this.applyCountLimitAndMergeRDates(dates, iterator);
|
|
972
|
+
}
|
|
973
|
+
const months = this.opts.byMonth.filter((v) => typeof v === "number").sort((a, b) => a - b);
|
|
974
|
+
let yearOffset = 0;
|
|
975
|
+
while (true) {
|
|
976
|
+
if (++iterationCount > this.maxIterations) {
|
|
977
|
+
throw new Error(`Maximum iterations (${this.maxIterations}) exceeded in all()`);
|
|
978
|
+
}
|
|
979
|
+
const year = start.year + yearOffset * this.opts.interval;
|
|
980
|
+
for (const month of months) {
|
|
981
|
+
let occ = start.with({ year, month });
|
|
982
|
+
occ = this.applyTimeOverride(occ);
|
|
983
|
+
if (import_temporal_polyfill.Temporal.ZonedDateTime.compare(occ, start) < 0) {
|
|
984
|
+
continue;
|
|
985
|
+
}
|
|
986
|
+
if (this.opts.until && import_temporal_polyfill.Temporal.ZonedDateTime.compare(occ, this.opts.until) > 0) {
|
|
987
|
+
return this.applyCountLimitAndMergeRDates(dates, iterator);
|
|
988
|
+
}
|
|
989
|
+
if (iterator && this.isExcluded(occ)) {
|
|
990
|
+
continue;
|
|
991
|
+
}
|
|
992
|
+
if (iterator && !iterator(occ, dates.length)) {
|
|
993
|
+
return this.applyCountLimitAndMergeRDates(dates, iterator);
|
|
994
|
+
}
|
|
995
|
+
dates.push(occ);
|
|
996
|
+
if (this.shouldBreakForCountLimit(dates.length)) {
|
|
997
|
+
return this.applyCountLimitAndMergeRDates(dates, iterator);
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
yearOffset++;
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
_allYearlyComplex(iterator) {
|
|
1004
|
+
const dates = [];
|
|
1005
|
+
let iterationCount = 0;
|
|
1006
|
+
const start = this.originalDtstart;
|
|
1007
|
+
if (!this.addDtstartIfNeeded(dates, iterator)) {
|
|
1008
|
+
return this.applyCountLimitAndMergeRDates(dates, iterator);
|
|
1009
|
+
}
|
|
1010
|
+
let yearCursor = start.with({ month: 1, day: 1 });
|
|
1011
|
+
while (true) {
|
|
1012
|
+
if (++iterationCount > this.maxIterations) {
|
|
1013
|
+
throw new Error(`Maximum iterations (${this.maxIterations}) exceeded in all()`);
|
|
1014
|
+
}
|
|
1015
|
+
const occs = this.generateYearlyOccurrences(yearCursor);
|
|
1016
|
+
const uniqueOccs = [];
|
|
1017
|
+
if (occs.length > 0) {
|
|
1018
|
+
uniqueOccs.push(occs[0]);
|
|
1019
|
+
for (let i = 1; i < occs.length; i++) {
|
|
1020
|
+
if (import_temporal_polyfill.Temporal.ZonedDateTime.compare(occs[i], occs[i - 1]) !== 0) {
|
|
1021
|
+
uniqueOccs.push(occs[i]);
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
const { shouldBreak } = this.processOccurrences(uniqueOccs, dates, start, iterator);
|
|
1026
|
+
if (shouldBreak) {
|
|
1027
|
+
break;
|
|
1028
|
+
}
|
|
1029
|
+
const interval = this.opts.freq === "WEEKLY" ? 1 : this.opts.interval;
|
|
1030
|
+
yearCursor = yearCursor.add({ years: interval });
|
|
1031
|
+
if (this.opts.freq === "WEEKLY" && this.opts.until && yearCursor.year > this.opts.until.year) {
|
|
1032
|
+
break;
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
return this.applyCountLimitAndMergeRDates(dates, iterator);
|
|
1036
|
+
}
|
|
1037
|
+
_allMinutelySecondlyComplex(iterator) {
|
|
1038
|
+
const dates = [];
|
|
1039
|
+
let iterationCount = 0;
|
|
1040
|
+
if (!this.addDtstartIfNeeded(dates, iterator)) {
|
|
1041
|
+
return this.applyCountLimitAndMergeRDates(dates, iterator);
|
|
1042
|
+
}
|
|
1043
|
+
let current = this.computeFirst();
|
|
1044
|
+
while (true) {
|
|
1045
|
+
if (++iterationCount > this.maxIterations) {
|
|
1046
|
+
throw new Error(`Maximum iterations (${this.maxIterations}) exceeded in all()`);
|
|
1047
|
+
}
|
|
1048
|
+
if (this.opts.until && import_temporal_polyfill.Temporal.ZonedDateTime.compare(current, this.opts.until) > 0) {
|
|
1049
|
+
break;
|
|
1050
|
+
}
|
|
1051
|
+
if (this.matchesAll(current)) {
|
|
1052
|
+
if (iterator && this.isExcluded(current)) {
|
|
1053
|
+
current = this.nextCandidateSameDate(current);
|
|
1054
|
+
continue;
|
|
1055
|
+
}
|
|
1056
|
+
if (iterator && !iterator(current, dates.length)) {
|
|
1057
|
+
break;
|
|
1058
|
+
}
|
|
1059
|
+
dates.push(current);
|
|
1060
|
+
if (this.shouldBreakForCountLimit(dates.length)) {
|
|
1061
|
+
break;
|
|
1062
|
+
}
|
|
1063
|
+
current = this.nextCandidateSameDate(current);
|
|
1064
|
+
} else {
|
|
1065
|
+
current = this.findNextValidDate(current);
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
return this.applyCountLimitAndMergeRDates(dates, iterator);
|
|
1069
|
+
}
|
|
1070
|
+
_allMonthlyByWeekNo(iterator) {
|
|
1071
|
+
const dates = [];
|
|
1072
|
+
let iterationCount = 0;
|
|
1073
|
+
const start = this.originalDtstart;
|
|
1074
|
+
if (!this.addDtstartIfNeeded(dates, iterator)) {
|
|
1075
|
+
return this.applyCountLimitAndMergeRDates(dates, iterator);
|
|
1076
|
+
}
|
|
1077
|
+
let current = start;
|
|
1078
|
+
const weekNos = [...this.opts.byWeekNo].sort((a, b) => a - b);
|
|
1079
|
+
const interval = this.opts.interval;
|
|
1080
|
+
let monthsAdvanced = 0;
|
|
1081
|
+
let lastYearProcessed = -1;
|
|
1082
|
+
outer_loop: while (true) {
|
|
1083
|
+
if (this.shouldBreakForCountLimit(dates.length)) {
|
|
1084
|
+
break;
|
|
1085
|
+
}
|
|
1086
|
+
if (++iterationCount > this.maxIterations) {
|
|
1087
|
+
throw new Error(`Maximum iterations (${this.maxIterations}) exceeded in all()`);
|
|
1088
|
+
}
|
|
1089
|
+
const year = current.year;
|
|
1090
|
+
if (year !== lastYearProcessed && current.month >= start.month) {
|
|
1091
|
+
lastYearProcessed = year;
|
|
1092
|
+
for (const weekNo of weekNos) {
|
|
1093
|
+
const occs = this.generateOccurrencesForWeekInYear(year, weekNo);
|
|
1094
|
+
for (const occ of occs) {
|
|
1095
|
+
if (import_temporal_polyfill.Temporal.ZonedDateTime.compare(occ, start) >= 0) {
|
|
1096
|
+
if (iterator && this.isExcluded(occ)) {
|
|
1097
|
+
continue;
|
|
1098
|
+
}
|
|
1099
|
+
if (iterator && !iterator(occ, dates.length)) {
|
|
1100
|
+
break outer_loop;
|
|
1101
|
+
}
|
|
1102
|
+
dates.push(occ);
|
|
1103
|
+
if (this.shouldBreakForCountLimit(dates.length)) {
|
|
1104
|
+
break outer_loop;
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
monthsAdvanced += interval;
|
|
1111
|
+
current = start.add({ months: monthsAdvanced });
|
|
1112
|
+
if (this.opts.until && import_temporal_polyfill.Temporal.ZonedDateTime.compare(current, this.opts.until) > 0) {
|
|
1113
|
+
break;
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
return this.applyCountLimitAndMergeRDates(dates, iterator);
|
|
1117
|
+
}
|
|
1118
|
+
_allMonthlyByYearDay(iterator) {
|
|
1119
|
+
const dates = [];
|
|
1120
|
+
let iterationCount = 0;
|
|
1121
|
+
const start = this.originalDtstart;
|
|
1122
|
+
if (!this.addDtstartIfNeeded(dates, iterator)) {
|
|
1123
|
+
return this.applyCountLimitAndMergeRDates(dates, iterator);
|
|
1124
|
+
}
|
|
1125
|
+
let year = start.year;
|
|
1126
|
+
const yearDays = [...this.opts.byYearDay].sort((a, b) => a - b);
|
|
1127
|
+
const interval = this.opts.interval;
|
|
1128
|
+
const startMonthAbs = start.year * 12 + start.month;
|
|
1129
|
+
outer_loop: while (true) {
|
|
1130
|
+
if (this.shouldBreakForCountLimit(dates.length)) {
|
|
1131
|
+
break;
|
|
1132
|
+
}
|
|
1133
|
+
if (++iterationCount > this.maxIterations) {
|
|
1134
|
+
throw new Error(`Maximum iterations (${this.maxIterations}) exceeded in all()`);
|
|
1135
|
+
}
|
|
1136
|
+
const yearStart = start.with({ year, month: 1, day: 1 });
|
|
1137
|
+
const lastDayOfYear = yearStart.with({ month: 12, day: 31 }).dayOfYear;
|
|
1138
|
+
for (const yd of yearDays) {
|
|
1139
|
+
const dayNum = yd > 0 ? yd : lastDayOfYear + yd + 1;
|
|
1140
|
+
if (dayNum <= 0 || dayNum > lastDayOfYear) continue;
|
|
1141
|
+
const baseOcc = yearStart.add({ days: dayNum - 1 });
|
|
1142
|
+
for (const occ of this.expandByTime(baseOcc)) {
|
|
1143
|
+
if (import_temporal_polyfill.Temporal.ZonedDateTime.compare(occ, start) < 0) continue;
|
|
1144
|
+
if (dates.some((d) => import_temporal_polyfill.Temporal.ZonedDateTime.compare(d, occ) === 0)) continue;
|
|
1145
|
+
const occMonthAbs = occ.year * 12 + occ.month;
|
|
1146
|
+
if ((occMonthAbs - startMonthAbs) % interval !== 0) {
|
|
1147
|
+
continue;
|
|
1148
|
+
}
|
|
1149
|
+
if (!this.matchesByMonth(occ)) {
|
|
1150
|
+
continue;
|
|
1151
|
+
}
|
|
1152
|
+
if (this.opts.until && import_temporal_polyfill.Temporal.ZonedDateTime.compare(occ, this.opts.until) > 0) {
|
|
1153
|
+
break outer_loop;
|
|
1154
|
+
}
|
|
1155
|
+
if (iterator && this.isExcluded(occ)) {
|
|
1156
|
+
continue;
|
|
1157
|
+
}
|
|
1158
|
+
if (iterator && !iterator(occ, dates.length)) {
|
|
1159
|
+
break outer_loop;
|
|
1160
|
+
}
|
|
1161
|
+
dates.push(occ);
|
|
1162
|
+
if (this.shouldBreakForCountLimit(dates.length)) {
|
|
1163
|
+
break outer_loop;
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
year++;
|
|
1168
|
+
if (this.opts.until && year > this.opts.until.year + 2) {
|
|
1169
|
+
break;
|
|
1170
|
+
}
|
|
1171
|
+
if (!this.opts.until && this.opts.count) {
|
|
1172
|
+
const yearsToScan = Math.ceil(this.opts.count / (this.opts.byYearDay.length || 1)) * interval + 5;
|
|
1173
|
+
if (year > start.year + yearsToScan) {
|
|
1174
|
+
break;
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
return this.applyCountLimitAndMergeRDates(dates, iterator);
|
|
1179
|
+
}
|
|
1180
|
+
_allDailyMinutelyHourlyWithBySetPos(iterator) {
|
|
1181
|
+
const dates = [];
|
|
1182
|
+
let iterationCount = 0;
|
|
1183
|
+
const start = this.originalDtstart;
|
|
1184
|
+
if (!this.addDtstartIfNeeded(dates, iterator)) {
|
|
1185
|
+
return this.applyCountLimitAndMergeRDates(dates, iterator);
|
|
1186
|
+
}
|
|
1187
|
+
let cursor;
|
|
1188
|
+
let duration;
|
|
1189
|
+
switch (this.opts.freq) {
|
|
1190
|
+
case "MINUTELY":
|
|
1191
|
+
cursor = start.with({ second: 0, microsecond: 0, nanosecond: 0 });
|
|
1192
|
+
duration = { minutes: this.opts.interval };
|
|
1193
|
+
break;
|
|
1194
|
+
case "HOURLY":
|
|
1195
|
+
cursor = start.with({ minute: 0, second: 0, microsecond: 0, nanosecond: 0 });
|
|
1196
|
+
duration = { hours: this.opts.interval };
|
|
1197
|
+
break;
|
|
1198
|
+
case "DAILY":
|
|
1199
|
+
cursor = start.with({ hour: 0, minute: 0, second: 0, microsecond: 0, nanosecond: 0 });
|
|
1200
|
+
duration = { days: this.opts.interval };
|
|
1201
|
+
break;
|
|
1202
|
+
default:
|
|
1203
|
+
return this.applyCountLimitAndMergeRDates(dates, iterator);
|
|
1204
|
+
}
|
|
1205
|
+
while (true) {
|
|
1206
|
+
if (++iterationCount > this.maxIterations) {
|
|
1207
|
+
throw new Error(`Maximum iterations (${this.maxIterations}) exceeded in all()`);
|
|
1208
|
+
}
|
|
1209
|
+
let periodOccs = this.expandByTime(cursor);
|
|
1210
|
+
periodOccs = periodOccs.filter((occ) => this.matchesAll(occ));
|
|
1211
|
+
periodOccs = this.applyBySetPos(periodOccs);
|
|
1212
|
+
const { shouldBreak } = this.processOccurrences(periodOccs, dates, start, iterator);
|
|
1213
|
+
if (shouldBreak) {
|
|
1214
|
+
break;
|
|
1215
|
+
}
|
|
1216
|
+
cursor = cursor.add(duration);
|
|
1217
|
+
if (this.opts.until && import_temporal_polyfill.Temporal.ZonedDateTime.compare(cursor, this.opts.until) > 0) {
|
|
1218
|
+
break;
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
return this.applyCountLimitAndMergeRDates(dates, iterator);
|
|
1222
|
+
}
|
|
1223
|
+
_allFallback(iterator) {
|
|
1224
|
+
const dates = [];
|
|
1225
|
+
let iterationCount = 0;
|
|
1226
|
+
let current = this.computeFirst();
|
|
1227
|
+
if (this.includeDtstart && import_temporal_polyfill.Temporal.ZonedDateTime.compare(current, this.originalDtstart) > 0) {
|
|
1228
|
+
if (iterator && this.isExcluded(this.originalDtstart)) {
|
|
1229
|
+
} else {
|
|
1230
|
+
if (iterator && !iterator(this.originalDtstart, dates.length)) {
|
|
1231
|
+
return this.applyCountLimitAndMergeRDates(dates, iterator);
|
|
1232
|
+
}
|
|
1233
|
+
dates.push(this.originalDtstart);
|
|
1234
|
+
if (this.shouldBreakForCountLimit(dates.length)) {
|
|
1235
|
+
return this.applyCountLimitAndMergeRDates(dates, iterator);
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
while (true) {
|
|
1240
|
+
if (++iterationCount > this.maxIterations) {
|
|
1241
|
+
throw new Error(`Maximum iterations (${this.maxIterations}) exceeded in all()`);
|
|
1242
|
+
}
|
|
1243
|
+
if (this.opts.until && import_temporal_polyfill.Temporal.ZonedDateTime.compare(current, this.opts.until) > 0) {
|
|
1244
|
+
break;
|
|
1245
|
+
}
|
|
1246
|
+
if (this.matchesAll(current)) {
|
|
1247
|
+
if (iterator && this.isExcluded(current)) {
|
|
1248
|
+
} else {
|
|
1249
|
+
if (iterator && !iterator(current, dates.length)) {
|
|
1250
|
+
break;
|
|
1251
|
+
}
|
|
1252
|
+
dates.push(current);
|
|
1253
|
+
if (this.shouldBreakForCountLimit(dates.length)) {
|
|
1254
|
+
break;
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
current = this.nextCandidateSameDate(current);
|
|
1259
|
+
}
|
|
1260
|
+
return this.applyCountLimitAndMergeRDates(dates, iterator);
|
|
1261
|
+
}
|
|
1262
|
+
/**
|
|
1263
|
+
* Returns all occurrences of the rule.
|
|
1264
|
+
* @param iterator - An optional callback iterator function that can be used to filter or modify the occurrences.
|
|
1265
|
+
* @returns An array of Temporal.ZonedDateTime objects representing all occurrences of the rule.
|
|
1266
|
+
*/
|
|
1267
|
+
all(iterator) {
|
|
1268
|
+
if (this.opts.rscale && ["CHINESE", "HEBREW", "INDIAN"].includes(this.opts.rscale)) {
|
|
1269
|
+
if (["YEARLY", "MONTHLY", "WEEKLY"].includes(this.opts.freq) || !!this.opts.byYearDay || !!this.opts.byWeekNo || this.opts.byMonthDay && this.opts.byMonthDay.length > 0) {
|
|
1270
|
+
return this._allRscaleNonGregorian(iterator);
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
if (this.opts.byWeekNo && this.opts.byYearDay) {
|
|
1274
|
+
const yearStart = this.originalDtstart.with({ month: 1, day: 1, hour: 0, minute: 0, second: 0, millisecond: 0 });
|
|
1275
|
+
const yearDays = this.opts.byYearDay.map((yd) => {
|
|
1276
|
+
const lastDayOfYear = yearStart.with({ month: 12, day: 31 }).dayOfYear;
|
|
1277
|
+
return yd > 0 ? yd : lastDayOfYear + yd + 1;
|
|
1278
|
+
});
|
|
1279
|
+
let possibleDate = false;
|
|
1280
|
+
for (const yd of yearDays) {
|
|
1281
|
+
const date = yearStart.add({ days: yd - 1 });
|
|
1282
|
+
if (this.matchesByWeekNo(date)) {
|
|
1283
|
+
possibleDate = true;
|
|
1284
|
+
break;
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
if (!possibleDate) {
|
|
1288
|
+
return [];
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
1291
|
+
if (!this.opts.count && !this.opts.until && !iterator) {
|
|
1292
|
+
throw new Error("all() requires iterator when no COUNT/UNTIL");
|
|
1293
|
+
}
|
|
1294
|
+
if (this.opts.freq === "MONTHLY" && (this.opts.byDay || this.opts.byMonthDay) && !this.opts.byWeekNo) {
|
|
1295
|
+
return this._allMonthlyByDayOrMonthDay(iterator);
|
|
1296
|
+
}
|
|
1297
|
+
if (this.opts.freq === "WEEKLY" && !(this.opts.byYearDay && this.opts.byYearDay.length > 0) && !(this.opts.byWeekNo && this.opts.byWeekNo.length > 0)) {
|
|
1298
|
+
return this._allWeekly(iterator);
|
|
1299
|
+
}
|
|
1300
|
+
if (this.opts.freq === "MONTHLY" && this.opts.byMonth && !this.opts.byDay && !this.opts.byMonthDay && !this.opts.byYearDay) {
|
|
1301
|
+
return this._allMonthlyByMonth(iterator);
|
|
1302
|
+
}
|
|
1303
|
+
if (this.opts.freq === "YEARLY" && this.opts.byMonth && !this.opts.byDay && !this.opts.byMonthDay && !this.opts.byYearDay && !this.opts.byWeekNo) {
|
|
1304
|
+
return this._allYearlyByMonth(iterator);
|
|
1305
|
+
}
|
|
1306
|
+
if (this.opts.freq === "YEARLY" && (this.opts.byDay || this.opts.byMonthDay || this.opts.byYearDay || this.opts.byWeekNo) || this.opts.freq === "WEEKLY" && this.opts.byYearDay && this.opts.byYearDay.length > 0 || this.opts.freq === "WEEKLY" && this.opts.byWeekNo && this.opts.byWeekNo.length > 0) {
|
|
1307
|
+
return this._allYearlyComplex(iterator);
|
|
1308
|
+
}
|
|
1309
|
+
if ((this.opts.freq === "MINUTELY" || this.opts.freq === "SECONDLY") && (this.opts.byMonth || this.opts.byWeekNo || this.opts.byYearDay || this.opts.byMonthDay || this.opts.byDay)) {
|
|
1310
|
+
return this._allMinutelySecondlyComplex(iterator);
|
|
1311
|
+
}
|
|
1312
|
+
if (this.opts.freq === "MONTHLY" && this.opts.byWeekNo && this.opts.byWeekNo.length > 0) {
|
|
1313
|
+
return this._allMonthlyByWeekNo(iterator);
|
|
1314
|
+
}
|
|
1315
|
+
if (this.opts.freq === "MONTHLY" && this.opts.byYearDay && this.opts.byYearDay.length > 0 && !this.opts.byDay && !this.opts.byMonthDay) {
|
|
1316
|
+
return this._allMonthlyByYearDay(iterator);
|
|
1317
|
+
}
|
|
1318
|
+
if (this.opts.rscale && this.opts.freq === "MONTHLY" && !this.opts.byDay && !this.opts.byMonthDay && !this.opts.byWeekNo && !this.opts.byYearDay) {
|
|
1319
|
+
return this._allMonthlyRscaleSimple(iterator);
|
|
1320
|
+
}
|
|
1321
|
+
if ((this.opts.freq === "MINUTELY" || this.opts.freq === "HOURLY" || this.opts.freq === "DAILY") && this.opts.bySetPos) {
|
|
1322
|
+
return this._allDailyMinutelyHourlyWithBySetPos(iterator);
|
|
1323
|
+
}
|
|
1324
|
+
return this._allFallback(iterator);
|
|
1325
|
+
}
|
|
1326
|
+
/**
|
|
1327
|
+
* RFC 7529: RSCALE present, simple monthly iteration with SKIP behavior.
|
|
1328
|
+
* Handles month-to-month stepping from DTSTART's year/month aiming for DTSTART's day-of-month.
|
|
1329
|
+
* Applies SKIP=OMIT (skip invalid months), BACKWARD (clamp to last day), FORWARD (first day of next month).
|
|
1330
|
+
*/
|
|
1331
|
+
_allMonthlyRscaleSimple(iterator) {
|
|
1332
|
+
var _a;
|
|
1333
|
+
const dates = [];
|
|
1334
|
+
let iterationCount = 0;
|
|
1335
|
+
const start = this.originalDtstart;
|
|
1336
|
+
const interval = (_a = this.opts.interval) != null ? _a : 1;
|
|
1337
|
+
const targetDom = start.day;
|
|
1338
|
+
if (!this.addDtstartIfNeeded(dates, iterator)) {
|
|
1339
|
+
return this.applyCountLimitAndMergeRDates(dates, iterator);
|
|
1340
|
+
}
|
|
1341
|
+
let cursor = start.with({ day: 1 });
|
|
1342
|
+
while (true) {
|
|
1343
|
+
if (++iterationCount > this.maxIterations) {
|
|
1344
|
+
throw new Error(`Maximum iterations (${this.maxIterations}) exceeded in all()`);
|
|
1345
|
+
}
|
|
1346
|
+
const lastDay = cursor.add({ months: 1 }).subtract({ days: 1 }).day;
|
|
1347
|
+
let occ = null;
|
|
1348
|
+
if (targetDom <= lastDay) {
|
|
1349
|
+
occ = cursor.with({ day: targetDom });
|
|
1350
|
+
} else {
|
|
1351
|
+
const skip = this.opts.skip || "OMIT";
|
|
1352
|
+
if (skip === "BACKWARD") {
|
|
1353
|
+
occ = cursor.with({ day: lastDay });
|
|
1354
|
+
} else if (skip === "FORWARD") {
|
|
1355
|
+
occ = cursor.add({ months: 1 }).with({ day: 1 });
|
|
1356
|
+
} else {
|
|
1357
|
+
occ = null;
|
|
1358
|
+
}
|
|
1359
|
+
}
|
|
1360
|
+
if (occ) {
|
|
1361
|
+
occ = occ.with({ hour: start.hour, minute: start.minute, second: start.second });
|
|
1362
|
+
if (!(iterator && this.isExcluded(occ))) {
|
|
1363
|
+
if (import_temporal_polyfill.Temporal.ZonedDateTime.compare(occ, start) >= 0) {
|
|
1364
|
+
if (!iterator || iterator(occ, dates.length)) {
|
|
1365
|
+
dates.push(occ);
|
|
1366
|
+
if (this.shouldBreakForCountLimit(dates.length)) break;
|
|
1367
|
+
} else {
|
|
1368
|
+
break;
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
cursor = cursor.add({ months: interval });
|
|
1374
|
+
if (this.opts.until && import_temporal_polyfill.Temporal.ZonedDateTime.compare(cursor, this.opts.until) > 0) {
|
|
1375
|
+
break;
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
return this.applyCountLimitAndMergeRDates(dates, iterator);
|
|
1379
|
+
}
|
|
1380
|
+
/**
|
|
1381
|
+
* Converts rDate entries to ZonedDateTime and merges with existing dates.
|
|
1382
|
+
* @param dates - Array of dates to merge with
|
|
1383
|
+
* @returns Merged and deduplicated array of dates
|
|
1384
|
+
*/
|
|
1385
|
+
mergeAndDeduplicateRDates(dates) {
|
|
1386
|
+
if (this.opts.rDate) {
|
|
1387
|
+
dates.push(...this.opts.rDate);
|
|
1388
|
+
}
|
|
1389
|
+
dates.sort((a, b) => import_temporal_polyfill.Temporal.ZonedDateTime.compare(a, b));
|
|
1390
|
+
const dedup = [];
|
|
1391
|
+
for (const d of dates) {
|
|
1392
|
+
if (dedup.length === 0 || import_temporal_polyfill.Temporal.ZonedDateTime.compare(d, dedup[dedup.length - 1]) !== 0) {
|
|
1393
|
+
dedup.push(d);
|
|
1394
|
+
}
|
|
1395
|
+
}
|
|
1396
|
+
return dedup;
|
|
1397
|
+
}
|
|
1398
|
+
/**
|
|
1399
|
+
* Checks if a date is in the exDate list.
|
|
1400
|
+
* @param date - Date to check
|
|
1401
|
+
* @returns True if the date is excluded
|
|
1402
|
+
*/
|
|
1403
|
+
isExcluded(date) {
|
|
1404
|
+
if (!this.opts.exDate || this.opts.exDate.length === 0) return false;
|
|
1405
|
+
return this.opts.exDate.some((exDate) => import_temporal_polyfill.Temporal.ZonedDateTime.compare(date, exDate) === 0);
|
|
1406
|
+
}
|
|
1407
|
+
/**
|
|
1408
|
+
* Excludes exDate entries from the given array of dates.
|
|
1409
|
+
* @param dates - Array of dates to filter
|
|
1410
|
+
* @returns Filtered array with exDate entries removed
|
|
1411
|
+
*/
|
|
1412
|
+
excludeExDates(dates) {
|
|
1413
|
+
if (!this.opts.exDate || this.opts.exDate.length === 0) return dates;
|
|
1414
|
+
return dates.filter((date) => {
|
|
1415
|
+
return !this.isExcluded(date);
|
|
1416
|
+
});
|
|
1417
|
+
}
|
|
1418
|
+
/**
|
|
1419
|
+
* Applies count limit and merges rDates with the rule-generated dates.
|
|
1420
|
+
* @param dates - Array of dates generated by the rule
|
|
1421
|
+
* @param iterator - Optional iterator function
|
|
1422
|
+
* @returns Final array of dates after merging and applying count limit
|
|
1423
|
+
*/
|
|
1424
|
+
applyCountLimitAndMergeRDates(dates, iterator) {
|
|
1425
|
+
const merged = this.mergeAndDeduplicateRDates(dates);
|
|
1426
|
+
const excluded = this.excludeExDates(merged);
|
|
1427
|
+
const hasCountLimit = this.opts.count !== void 0;
|
|
1428
|
+
if (!hasCountLimit && !iterator) {
|
|
1429
|
+
return excluded;
|
|
1430
|
+
}
|
|
1431
|
+
let emitted = 0;
|
|
1432
|
+
const max = hasCountLimit ? this.opts.count : Infinity;
|
|
1433
|
+
const finalDates = [];
|
|
1434
|
+
for (const d of excluded) {
|
|
1435
|
+
if (emitted >= max) break;
|
|
1436
|
+
if (iterator && !iterator(d, emitted)) break;
|
|
1437
|
+
finalDates.push(d);
|
|
1438
|
+
emitted++;
|
|
1439
|
+
}
|
|
1440
|
+
return finalDates;
|
|
1441
|
+
}
|
|
1442
|
+
/**
|
|
1443
|
+
* Checks if the count limit should break the loop based on rDate presence.
|
|
1444
|
+
* @param matchCount - Current number of matches
|
|
1445
|
+
* @returns true if the loop should break
|
|
1446
|
+
*/
|
|
1447
|
+
shouldBreakForCountLimit(matchCount) {
|
|
1448
|
+
if (this.opts.count === void 0) return false;
|
|
1449
|
+
if (!this.opts.rDate) {
|
|
1450
|
+
return matchCount >= this.opts.count;
|
|
1451
|
+
}
|
|
1452
|
+
const rDateCount = this.opts.rDate.length;
|
|
1453
|
+
const targetRuleCount = Math.max(this.opts.count - rDateCount, 0);
|
|
1454
|
+
const safetyMargin = Math.min(targetRuleCount, 10);
|
|
1455
|
+
return matchCount >= targetRuleCount + safetyMargin;
|
|
1456
|
+
}
|
|
1457
|
+
/**
|
|
1458
|
+
* Returns all occurrences of the rule within a specified time window.
|
|
1459
|
+
* @param after - The start date or Temporal.ZonedDateTime object.
|
|
1460
|
+
* @param before - The end date or Temporal.ZonedDateTime object.
|
|
1461
|
+
* @param inc - Optional boolean flag to include the end date in the results.
|
|
1462
|
+
* @returns An array of Temporal.ZonedDateTime objects representing all occurrences of the rule within the specified time window.
|
|
1463
|
+
*/
|
|
1464
|
+
between(after, before, inc = false) {
|
|
1465
|
+
var _a;
|
|
1466
|
+
const startInst = after instanceof Date ? import_temporal_polyfill.Temporal.Instant.from(after.toISOString()) : after.toInstant();
|
|
1467
|
+
const endInst = before instanceof Date ? import_temporal_polyfill.Temporal.Instant.from(before.toISOString()) : before.toInstant();
|
|
1468
|
+
const startZdt = import_temporal_polyfill.Temporal.Instant.from(startInst).toZonedDateTimeISO(this.tzid);
|
|
1469
|
+
const beforeZdt = import_temporal_polyfill.Temporal.Instant.from(endInst).toZonedDateTimeISO(this.tzid);
|
|
1470
|
+
const tempOpts = __spreadValues({}, this.opts);
|
|
1471
|
+
if (!tempOpts.until || import_temporal_polyfill.Temporal.ZonedDateTime.compare(beforeZdt, tempOpts.until) < 0) {
|
|
1472
|
+
tempOpts.until = beforeZdt;
|
|
1473
|
+
}
|
|
1474
|
+
if (tempOpts.count === void 0) {
|
|
1475
|
+
const interval = (_a = tempOpts.interval) != null ? _a : 1;
|
|
1476
|
+
const aligned = startZdt.withPlainTime(this.originalDtstart.toPlainTime());
|
|
1477
|
+
let unit;
|
|
1478
|
+
switch (tempOpts.freq) {
|
|
1479
|
+
case "YEARLY":
|
|
1480
|
+
unit = "years";
|
|
1481
|
+
break;
|
|
1482
|
+
case "MONTHLY":
|
|
1483
|
+
unit = "months";
|
|
1484
|
+
break;
|
|
1485
|
+
case "WEEKLY":
|
|
1486
|
+
unit = "weeks";
|
|
1487
|
+
break;
|
|
1488
|
+
case "DAILY":
|
|
1489
|
+
unit = "days";
|
|
1490
|
+
break;
|
|
1491
|
+
case "HOURLY":
|
|
1492
|
+
unit = "hours";
|
|
1493
|
+
break;
|
|
1494
|
+
case "MINUTELY":
|
|
1495
|
+
unit = "minutes";
|
|
1496
|
+
break;
|
|
1497
|
+
default:
|
|
1498
|
+
unit = "seconds";
|
|
1499
|
+
}
|
|
1500
|
+
const diffDur = this.opts.dtstart.until(aligned, { largestUnit: unit });
|
|
1501
|
+
const unitsBetween = diffDur[unit];
|
|
1502
|
+
const steps = Math.floor(unitsBetween / interval);
|
|
1503
|
+
let toAdd;
|
|
1504
|
+
const jump = steps * interval;
|
|
1505
|
+
switch (unit) {
|
|
1506
|
+
case "years":
|
|
1507
|
+
toAdd = { years: jump };
|
|
1508
|
+
break;
|
|
1509
|
+
case "months":
|
|
1510
|
+
toAdd = { months: jump };
|
|
1511
|
+
break;
|
|
1512
|
+
case "weeks":
|
|
1513
|
+
toAdd = { weeks: jump };
|
|
1514
|
+
break;
|
|
1515
|
+
case "days":
|
|
1516
|
+
toAdd = { days: jump };
|
|
1517
|
+
break;
|
|
1518
|
+
case "hours":
|
|
1519
|
+
toAdd = { hours: jump };
|
|
1520
|
+
break;
|
|
1521
|
+
case "minutes":
|
|
1522
|
+
toAdd = { minutes: jump };
|
|
1523
|
+
break;
|
|
1524
|
+
default:
|
|
1525
|
+
toAdd = { seconds: jump };
|
|
1526
|
+
}
|
|
1527
|
+
let candidate = this.opts.dtstart.add(toAdd);
|
|
1528
|
+
if (import_temporal_polyfill.Temporal.ZonedDateTime.compare(candidate, this.opts.dtstart) < 0) {
|
|
1529
|
+
candidate = this.opts.dtstart;
|
|
1530
|
+
}
|
|
1531
|
+
tempOpts.dtstart = candidate;
|
|
1532
|
+
}
|
|
1533
|
+
const tempRule = new _RRuleTemporal(tempOpts);
|
|
1534
|
+
const allDates = tempRule.all();
|
|
1535
|
+
return allDates.filter((date) => {
|
|
1536
|
+
const inst = date.toInstant();
|
|
1537
|
+
const afterStart = inc ? import_temporal_polyfill.Temporal.Instant.compare(inst, startInst) >= 0 : import_temporal_polyfill.Temporal.Instant.compare(inst, startInst) > 0;
|
|
1538
|
+
const beforeEnd = inc ? import_temporal_polyfill.Temporal.Instant.compare(inst, endInst) <= 0 : import_temporal_polyfill.Temporal.Instant.compare(inst, endInst) < 0;
|
|
1539
|
+
return afterStart && beforeEnd;
|
|
1540
|
+
});
|
|
1541
|
+
}
|
|
1542
|
+
/**
|
|
1543
|
+
* Returns the next occurrence of the rule after a specified date.
|
|
1544
|
+
* @param after - The start date or Temporal.ZonedDateTime object.
|
|
1545
|
+
* @param inc - Optional boolean flag to include occurrences on the start date.
|
|
1546
|
+
* @returns The next occurrence of the rule after the specified date or null if no occurrences are found.
|
|
1547
|
+
*/
|
|
1548
|
+
next(after = /* @__PURE__ */ new Date(), inc = false) {
|
|
1549
|
+
const afterInst = after instanceof Date ? import_temporal_polyfill.Temporal.Instant.from(after.toISOString()) : after.toInstant();
|
|
1550
|
+
let result = null;
|
|
1551
|
+
this.all((occ) => {
|
|
1552
|
+
const inst = occ.toInstant();
|
|
1553
|
+
const ok = inc ? import_temporal_polyfill.Temporal.Instant.compare(inst, afterInst) >= 0 : import_temporal_polyfill.Temporal.Instant.compare(inst, afterInst) > 0;
|
|
1554
|
+
if (ok) {
|
|
1555
|
+
if (!result || import_temporal_polyfill.Temporal.ZonedDateTime.compare(occ, result) < 0) {
|
|
1556
|
+
result = occ;
|
|
1557
|
+
}
|
|
1558
|
+
return false;
|
|
1559
|
+
}
|
|
1560
|
+
return true;
|
|
1561
|
+
});
|
|
1562
|
+
return result;
|
|
1563
|
+
}
|
|
1564
|
+
/**
|
|
1565
|
+
* Returns the previous occurrence of the rule before a specified date.
|
|
1566
|
+
* @param before - The end date or Temporal.ZonedDateTime object.
|
|
1567
|
+
* @param inc - Optional boolean flag to include occurrences on the end date.
|
|
1568
|
+
* @returns The previous occurrence of the rule before the specified date or null if no occurrences are found.
|
|
1569
|
+
*/
|
|
1570
|
+
previous(before = /* @__PURE__ */ new Date(), inc = false) {
|
|
1571
|
+
const beforeInst = before instanceof Date ? import_temporal_polyfill.Temporal.Instant.from(before.toISOString()) : before.toInstant();
|
|
1572
|
+
let prev = null;
|
|
1573
|
+
this.all((occ) => {
|
|
1574
|
+
const inst = occ.toInstant();
|
|
1575
|
+
const beyond = inc ? import_temporal_polyfill.Temporal.Instant.compare(inst, beforeInst) > 0 : import_temporal_polyfill.Temporal.Instant.compare(inst, beforeInst) >= 0;
|
|
1576
|
+
if (beyond) return false;
|
|
1577
|
+
prev = occ;
|
|
1578
|
+
return true;
|
|
1579
|
+
});
|
|
1580
|
+
return prev;
|
|
1581
|
+
}
|
|
1582
|
+
toString() {
|
|
1583
|
+
const iso = this.originalDtstart.toString({ smallestUnit: "second" }).replace(/[-:]/g, "");
|
|
1584
|
+
const dtLine = `DTSTART;TZID=${this.tzid}:${iso.slice(0, 15)}`;
|
|
1585
|
+
const rule = [];
|
|
1586
|
+
const {
|
|
1587
|
+
freq,
|
|
1588
|
+
interval,
|
|
1589
|
+
count,
|
|
1590
|
+
until,
|
|
1591
|
+
byHour,
|
|
1592
|
+
byMinute,
|
|
1593
|
+
bySecond,
|
|
1594
|
+
byDay,
|
|
1595
|
+
byMonth,
|
|
1596
|
+
byMonthDay,
|
|
1597
|
+
bySetPos,
|
|
1598
|
+
byWeekNo,
|
|
1599
|
+
byYearDay,
|
|
1600
|
+
wkst,
|
|
1601
|
+
rDate,
|
|
1602
|
+
exDate
|
|
1603
|
+
} = this.opts;
|
|
1604
|
+
if (this.opts.rscale) rule.push(`RSCALE=${this.opts.rscale}`);
|
|
1605
|
+
if (this.opts.rscale && this.opts.skip) rule.push(`SKIP=${this.opts.skip}`);
|
|
1606
|
+
rule.push(`FREQ=${freq}`);
|
|
1607
|
+
if (interval !== 1) rule.push(`INTERVAL=${interval}`);
|
|
1608
|
+
if (count !== void 0) rule.push(`COUNT=${count}`);
|
|
1609
|
+
if (until) {
|
|
1610
|
+
rule.push(`UNTIL=${this.formatIcsDateTime(until)}`);
|
|
1611
|
+
}
|
|
1612
|
+
if (byHour) rule.push(`BYHOUR=${byHour.join(",")}`);
|
|
1613
|
+
if (byMinute) rule.push(`BYMINUTE=${byMinute.join(",")}`);
|
|
1614
|
+
if (bySecond) rule.push(`BYSECOND=${bySecond.join(",")}`);
|
|
1615
|
+
if (byDay) rule.push(`BYDAY=${byDay.join(",")}`);
|
|
1616
|
+
if (byMonth) rule.push(`BYMONTH=${byMonth.join(",")}`);
|
|
1617
|
+
if (byMonthDay) rule.push(`BYMONTHDAY=${byMonthDay.join(",")}`);
|
|
1618
|
+
if (bySetPos) rule.push(`BYSETPOS=${bySetPos.join(",")}`);
|
|
1619
|
+
if (byWeekNo) rule.push(`BYWEEKNO=${byWeekNo.join(",")}`);
|
|
1620
|
+
if (byYearDay) rule.push(`BYYEARDAY=${byYearDay.join(",")}`);
|
|
1621
|
+
if (wkst) rule.push(`WKST=${wkst}`);
|
|
1622
|
+
const lines = [dtLine, `RRULE:${rule.join(";")}`];
|
|
1623
|
+
if (rDate) {
|
|
1624
|
+
lines.push(`RDATE:${this.joinDates(rDate)}`);
|
|
1625
|
+
}
|
|
1626
|
+
if (exDate) {
|
|
1627
|
+
lines.push(`EXDATE:${this.joinDates(exDate)}`);
|
|
1628
|
+
}
|
|
1629
|
+
return lines.join("\n");
|
|
1630
|
+
}
|
|
1631
|
+
formatIcsDateTime(date) {
|
|
1632
|
+
return date.toInstant().toString().replace(/[-:]/g, "").slice(0, 15) + "Z";
|
|
1633
|
+
}
|
|
1634
|
+
joinDates(dates) {
|
|
1635
|
+
return dates.map((d) => this.formatIcsDateTime(d));
|
|
1636
|
+
}
|
|
1637
|
+
/**
|
|
1638
|
+
* Given any date in a month, return all the ZonedDateTimes in that month
|
|
1639
|
+
* matching your opts.byDay and opts.byMonth (or the single "same day" if no BYDAY).
|
|
1640
|
+
*/
|
|
1641
|
+
generateMonthlyOccurrences(sample) {
|
|
1642
|
+
var _a;
|
|
1643
|
+
const { byDay, byMonth, byMonthDay } = this.opts;
|
|
1644
|
+
if (byMonth && !byMonth.includes(sample.month)) return [];
|
|
1645
|
+
const lastDay = sample.with({ day: 1 }).add({ months: 1 }).subtract({ days: 1 }).day;
|
|
1646
|
+
let byMonthDayHits = [];
|
|
1647
|
+
if (byMonthDay && byMonthDay.length > 0) {
|
|
1648
|
+
byMonthDayHits = byMonthDay.map((d) => d > 0 ? d : lastDay + d + 1).filter((d) => d >= 1 && d <= lastDay);
|
|
1649
|
+
}
|
|
1650
|
+
if (!byDay && byMonthDay && byMonthDay.length > 0) {
|
|
1651
|
+
if (byMonthDayHits.length === 0) {
|
|
1652
|
+
return [];
|
|
1653
|
+
}
|
|
1654
|
+
const dates = byMonthDayHits.map((d) => sample.with({ day: d }));
|
|
1655
|
+
return dates.flatMap((z) => this.expandByTime(z)).sort((a, b) => import_temporal_polyfill.Temporal.ZonedDateTime.compare(a, b));
|
|
1656
|
+
}
|
|
1657
|
+
if (!byDay) {
|
|
1658
|
+
return this.expandByTime(sample);
|
|
1659
|
+
}
|
|
1660
|
+
const dayMap = { MO: 1, TU: 2, WE: 3, TH: 4, FR: 5, SA: 6, SU: 7 };
|
|
1661
|
+
const tokens = byDay.map((tok) => {
|
|
1662
|
+
const m = tok.match(/^([+-]?\d{1,2})?(MO|TU|WE|TH|FR|SA|SU)$/);
|
|
1663
|
+
if (!m) return null;
|
|
1664
|
+
return { ord: m[1] ? parseInt(m[1], 10) : 0, wd: dayMap[m[2]] };
|
|
1665
|
+
}).filter((x) => x !== null);
|
|
1666
|
+
const buckets = {};
|
|
1667
|
+
let cursor = sample.with({ day: 1 });
|
|
1668
|
+
while (cursor.month === sample.month) {
|
|
1669
|
+
const dow = cursor.dayOfWeek;
|
|
1670
|
+
(buckets[dow] || (buckets[dow] = [])).push(cursor.day);
|
|
1671
|
+
cursor = cursor.add({ days: 1 });
|
|
1672
|
+
}
|
|
1673
|
+
const byDayHits = [];
|
|
1674
|
+
for (const { ord, wd } of tokens) {
|
|
1675
|
+
const list = (_a = buckets[wd]) != null ? _a : [];
|
|
1676
|
+
if (!list.length) continue;
|
|
1677
|
+
if (ord === 0) {
|
|
1678
|
+
for (const d of list) byDayHits.push(d);
|
|
1679
|
+
} else {
|
|
1680
|
+
const idx = ord > 0 ? ord - 1 : list.length + ord;
|
|
1681
|
+
const dayN = list[idx];
|
|
1682
|
+
if (dayN) byDayHits.push(dayN);
|
|
1683
|
+
}
|
|
1684
|
+
}
|
|
1685
|
+
let finalDays = byDayHits;
|
|
1686
|
+
if (byMonthDay && byMonthDay.length > 0) {
|
|
1687
|
+
if (byMonthDayHits.length === 0) {
|
|
1688
|
+
return [];
|
|
1689
|
+
}
|
|
1690
|
+
finalDays = finalDays.filter((d) => byMonthDayHits.includes(d));
|
|
1691
|
+
}
|
|
1692
|
+
const hits = finalDays.map((d) => sample.with({ day: d }));
|
|
1693
|
+
return hits.flatMap((z) => this.expandByTime(z)).sort((a, b) => import_temporal_polyfill.Temporal.ZonedDateTime.compare(a, b));
|
|
1694
|
+
}
|
|
1695
|
+
/**
|
|
1696
|
+
* Given any date in a year, return all ZonedDateTimes in that year matching
|
|
1697
|
+
* the BYDAY/BYMONTHDAY/BYMONTH constraints. Months default to DTSTART's month
|
|
1698
|
+
* if BYMONTH is not specified.
|
|
1699
|
+
*/
|
|
1700
|
+
generateYearlyOccurrences(sample) {
|
|
1701
|
+
const months = this.opts.byMonth ? this.opts.byMonth.filter((v) => typeof v === "number").sort((a, b) => a - b) : this.opts.byMonthDay || this.opts.byDay ? [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] : [this.originalDtstart.month];
|
|
1702
|
+
let occs = [];
|
|
1703
|
+
const hasOrdinalByDay = this.opts.byDay && this.opts.byDay.some((t) => /^[+-]?\d/.test(t));
|
|
1704
|
+
if (hasOrdinalByDay && !this.opts.byMonth) {
|
|
1705
|
+
const dayMap = { MO: 1, TU: 2, WE: 3, TH: 4, FR: 5, SA: 6, SU: 7 };
|
|
1706
|
+
for (const tok of this.opts.byDay) {
|
|
1707
|
+
const m = tok.match(/^([+-]?\d{1,2})(MO|TU|WE|TH|FR|SA|SU)$/);
|
|
1708
|
+
if (!m) continue;
|
|
1709
|
+
const ord = parseInt(m[1], 10);
|
|
1710
|
+
const wd = dayMap[m[2]];
|
|
1711
|
+
let dt;
|
|
1712
|
+
if (ord > 0) {
|
|
1713
|
+
const jan1 = sample.with({ month: 1, day: 1 });
|
|
1714
|
+
const delta = (wd - jan1.dayOfWeek + 7) % 7;
|
|
1715
|
+
dt = jan1.add({ days: delta + 7 * (ord - 1) });
|
|
1716
|
+
} else {
|
|
1717
|
+
const dec31 = sample.with({ month: 12, day: 31 });
|
|
1718
|
+
const delta = (dec31.dayOfWeek - wd + 7) % 7;
|
|
1719
|
+
dt = dec31.subtract({ days: delta + 7 * (-ord - 1) });
|
|
1720
|
+
}
|
|
1721
|
+
occs.push(...this.expandByTime(dt));
|
|
1722
|
+
}
|
|
1723
|
+
} else if (!this.opts.byYearDay && !this.opts.byWeekNo) {
|
|
1724
|
+
occs = [];
|
|
1725
|
+
for (const m of months) {
|
|
1726
|
+
const monthSample = sample.with({ month: m, day: 1 });
|
|
1727
|
+
const monthOccs = this.generateMonthlyOccurrences(monthSample);
|
|
1728
|
+
if (monthOccs.length === 0 && this.opts.rscale && this.opts.byMonthDay && this.opts.byMonthDay.length > 0) {
|
|
1729
|
+
const lastDay = monthSample.add({ months: 1 }).subtract({ days: 1 }).day;
|
|
1730
|
+
const target = this.opts.byMonthDay[0];
|
|
1731
|
+
const absTarget = target > 0 ? target : lastDay + target + 1;
|
|
1732
|
+
if (absTarget > lastDay || absTarget <= 0) {
|
|
1733
|
+
const skip = this.opts.skip || "OMIT";
|
|
1734
|
+
if (skip === "BACKWARD") {
|
|
1735
|
+
occs.push(...this.expandByTime(monthSample.with({ day: lastDay })));
|
|
1736
|
+
} else if (skip === "FORWARD") {
|
|
1737
|
+
const nextMonth = monthSample.add({ months: 1 }).with({ day: 1 });
|
|
1738
|
+
occs.push(...this.expandByTime(nextMonth));
|
|
1739
|
+
} else {
|
|
1740
|
+
}
|
|
1741
|
+
}
|
|
1742
|
+
} else {
|
|
1743
|
+
occs.push(...monthOccs);
|
|
1744
|
+
}
|
|
1745
|
+
}
|
|
1746
|
+
}
|
|
1747
|
+
if (this.opts.byYearDay) {
|
|
1748
|
+
const last = sample.with({ month: 12, day: 31 }).dayOfYear;
|
|
1749
|
+
for (const d of this.opts.byYearDay) {
|
|
1750
|
+
const dayNum = d > 0 ? d : last + d + 1;
|
|
1751
|
+
if (dayNum <= 0 || dayNum > last) continue;
|
|
1752
|
+
const dt = this.opts.freq === "MINUTELY" ? sample.with({ month: 1, day: 1, hour: 0, minute: 0, second: 0, millisecond: 0 }).add({ days: dayNum - 1 }) : sample.with({ month: 1, day: 1 }).add({ days: dayNum - 1 });
|
|
1753
|
+
if (!this.opts.byMonth || this.opts.byMonth.includes(dt.month)) {
|
|
1754
|
+
occs.push(...this.expandByTime(dt));
|
|
1755
|
+
}
|
|
1756
|
+
}
|
|
1757
|
+
}
|
|
1758
|
+
if (this.opts.byWeekNo) {
|
|
1759
|
+
const { lastWeek, firstWeekStart, tokens } = this.isoWeekByDay(sample);
|
|
1760
|
+
for (const weekNo of this.opts.byWeekNo) {
|
|
1761
|
+
if (weekNo > 0 && weekNo > lastWeek || weekNo < 0 && -weekNo > lastWeek) {
|
|
1762
|
+
continue;
|
|
1763
|
+
}
|
|
1764
|
+
const weekIndex = weekNo > 0 ? weekNo - 1 : lastWeek + weekNo;
|
|
1765
|
+
const weekStart = firstWeekStart.add({ weeks: weekIndex });
|
|
1766
|
+
occs.push(...this.addByDay(tokens, weekStart));
|
|
1767
|
+
}
|
|
1768
|
+
}
|
|
1769
|
+
occs = occs.sort((a, b) => import_temporal_polyfill.Temporal.ZonedDateTime.compare(a, b));
|
|
1770
|
+
occs = this.applyBySetPos(occs);
|
|
1771
|
+
return occs;
|
|
1772
|
+
}
|
|
1773
|
+
addByDay(tokens, weekStart) {
|
|
1774
|
+
const dayMap = { MO: 1, TU: 2, WE: 3, TH: 4, FR: 5, SA: 6, SU: 7 };
|
|
1775
|
+
const wkst = dayMap[this.opts.wkst || "MO"];
|
|
1776
|
+
const entries = [];
|
|
1777
|
+
for (const tok of tokens) {
|
|
1778
|
+
if (!tok) continue;
|
|
1779
|
+
const targetDow = dayMap[tok];
|
|
1780
|
+
const inst = weekStart.add({ days: (targetDow - wkst + 7) % 7 });
|
|
1781
|
+
if (!this.opts.byMonth || this.opts.byMonth.includes(inst.month)) {
|
|
1782
|
+
entries.push(...this.expandByTime(inst));
|
|
1783
|
+
}
|
|
1784
|
+
}
|
|
1785
|
+
return entries;
|
|
1786
|
+
}
|
|
1787
|
+
/**
|
|
1788
|
+
* Helper to find the next valid value from a sorted array
|
|
1789
|
+
*/
|
|
1790
|
+
findNextValidValue(currentValue, validValues, compare) {
|
|
1791
|
+
return validValues.find((v) => compare(v, currentValue) > 0) || null;
|
|
1792
|
+
}
|
|
1793
|
+
/**
|
|
1794
|
+
* Efficiently find the next valid date for MINUTELY and SECONDLY frequency by jumping over
|
|
1795
|
+
* large gaps when BYXXX constraints don't match.
|
|
1796
|
+
*/
|
|
1797
|
+
findNextValidDate(current) {
|
|
1798
|
+
if (this.opts.byWeekNo && this.opts.byYearDay) {
|
|
1799
|
+
const yearStart = current.with({ month: 1, day: 1, hour: 0, minute: 0, second: 0, millisecond: 0 });
|
|
1800
|
+
const yearDays = this.opts.byYearDay.map((yd) => {
|
|
1801
|
+
const lastDayOfYear = yearStart.with({ month: 12, day: 31 }).dayOfYear;
|
|
1802
|
+
return yd > 0 ? yd : lastDayOfYear + yd + 1;
|
|
1803
|
+
});
|
|
1804
|
+
for (const yd of yearDays) {
|
|
1805
|
+
const date = yearStart.add({ days: yd - 1 });
|
|
1806
|
+
if (this.matchesByWeekNo(date)) {
|
|
1807
|
+
break;
|
|
1808
|
+
}
|
|
1809
|
+
}
|
|
1810
|
+
}
|
|
1811
|
+
if (this.opts.byMonth) {
|
|
1812
|
+
const numericMonths = this.opts.byMonth.filter((v) => typeof v === "number");
|
|
1813
|
+
if (numericMonths.length && !numericMonths.includes(current.month)) {
|
|
1814
|
+
const months = [...numericMonths].sort((a, b) => a - b);
|
|
1815
|
+
const nextMonth = this.findNextValidValue(current.month, months, (a, b) => a - b);
|
|
1816
|
+
if (nextMonth) {
|
|
1817
|
+
current = current.with({ month: nextMonth, day: 1, hour: 0, minute: 0, second: 0 });
|
|
1818
|
+
} else {
|
|
1819
|
+
current = current.add({ years: 1 }).with({ month: months[0], day: 1, hour: 0, minute: 0, second: 0 });
|
|
1820
|
+
}
|
|
1821
|
+
current = this.applyTimeOverride(current);
|
|
1822
|
+
return current;
|
|
1823
|
+
}
|
|
1824
|
+
}
|
|
1825
|
+
if (this.opts.byWeekNo && !this.matchesByWeekNo(current)) {
|
|
1826
|
+
current = current.add({ weeks: 1 }).with({ hour: 0, minute: 0, second: 0 });
|
|
1827
|
+
current = this.applyTimeOverride(current);
|
|
1828
|
+
return current;
|
|
1829
|
+
}
|
|
1830
|
+
if (this.opts.byYearDay && !this.matchesByYearDay(current)) {
|
|
1831
|
+
const yearDays = [...this.opts.byYearDay].sort((a, b) => a - b);
|
|
1832
|
+
const currentYearDay = current.dayOfYear;
|
|
1833
|
+
const lastDayOfYear = current.with({ month: 12, day: 31 }).dayOfYear;
|
|
1834
|
+
let nextYearDay = yearDays.find((d) => {
|
|
1835
|
+
const dayNum = d > 0 ? d : lastDayOfYear + d + 1;
|
|
1836
|
+
return dayNum > currentYearDay;
|
|
1837
|
+
});
|
|
1838
|
+
if (nextYearDay) {
|
|
1839
|
+
const dayNum = nextYearDay > 0 ? nextYearDay : lastDayOfYear + nextYearDay + 1;
|
|
1840
|
+
if (this.opts.freq === "MINUTELY" || this.opts.freq === "SECONDLY") {
|
|
1841
|
+
current = current.with({ month: 1, day: 1, hour: 0, minute: 0, second: 0, millisecond: 0 }).add({ days: dayNum - 1 });
|
|
1842
|
+
} else {
|
|
1843
|
+
current = current.with({ month: 1, day: 1 }).add({ days: dayNum - 1 });
|
|
1844
|
+
}
|
|
1845
|
+
} else {
|
|
1846
|
+
const nextYear = current.add({ years: 1 });
|
|
1847
|
+
const nextYearLastDay = nextYear.with({ month: 12, day: 31 }).dayOfYear;
|
|
1848
|
+
const firstYearDay = yearDays[0];
|
|
1849
|
+
if (firstYearDay !== void 0) {
|
|
1850
|
+
const dayNum = firstYearDay > 0 ? firstYearDay : nextYearLastDay + firstYearDay + 1;
|
|
1851
|
+
if (this.opts.freq === "MINUTELY" || this.opts.freq === "SECONDLY") {
|
|
1852
|
+
current = nextYear.with({ month: 1, day: 1, hour: 0, minute: 0, second: 0, millisecond: 0 }).add({ days: dayNum - 1 });
|
|
1853
|
+
} else {
|
|
1854
|
+
current = nextYear.with({ month: 1, day: 1 }).add({ days: dayNum - 1 });
|
|
1855
|
+
}
|
|
1856
|
+
}
|
|
1857
|
+
}
|
|
1858
|
+
current = this.applyTimeOverride(current);
|
|
1859
|
+
return current;
|
|
1860
|
+
}
|
|
1861
|
+
if (this.opts.byMonthDay && !this.matchesByMonthDay(current)) {
|
|
1862
|
+
const monthDays = [...this.opts.byMonthDay].sort((a, b) => a - b);
|
|
1863
|
+
const lastDayOfMonth = current.with({ day: 1 }).add({ months: 1 }).subtract({ days: 1 }).day;
|
|
1864
|
+
const currentDay = current.day;
|
|
1865
|
+
const validDays = monthDays.map((d) => d > 0 ? d : lastDayOfMonth + d + 1).filter((d) => d > 0 && d <= lastDayOfMonth).sort((a, b) => a - b);
|
|
1866
|
+
const nextDay = this.findNextValidValue(currentDay, validDays, (a, b) => a - b);
|
|
1867
|
+
if (nextDay) {
|
|
1868
|
+
current = current.with({ day: nextDay, hour: 0, minute: 0, second: 0 });
|
|
1869
|
+
} else {
|
|
1870
|
+
const nextMonth = current.add({ months: 1 }).with({ day: 1 });
|
|
1871
|
+
const nextMonthLastDay = nextMonth.add({ months: 1 }).subtract({ days: 1 }).day;
|
|
1872
|
+
const firstMonthDay = monthDays[0];
|
|
1873
|
+
if (firstMonthDay !== void 0) {
|
|
1874
|
+
const dayNum = firstMonthDay > 0 ? firstMonthDay : nextMonthLastDay + firstMonthDay + 1;
|
|
1875
|
+
current = nextMonth.with({
|
|
1876
|
+
day: Math.max(1, Math.min(dayNum, nextMonthLastDay)),
|
|
1877
|
+
hour: 0,
|
|
1878
|
+
minute: 0,
|
|
1879
|
+
second: 0
|
|
1880
|
+
});
|
|
1881
|
+
} else {
|
|
1882
|
+
current = current.add({ months: 1 }).with({ day: 1, hour: 0, minute: 0, second: 0 });
|
|
1883
|
+
}
|
|
1884
|
+
}
|
|
1885
|
+
current = this.applyTimeOverride(current);
|
|
1886
|
+
return current;
|
|
1887
|
+
}
|
|
1888
|
+
if (this.opts.byDay && !this.matchesByDay(current)) {
|
|
1889
|
+
const dayMap = { MO: 1, TU: 2, WE: 3, TH: 4, FR: 5, SA: 6, SU: 7 };
|
|
1890
|
+
const targetDays = this.opts.byDay.map((tok) => {
|
|
1891
|
+
var _a;
|
|
1892
|
+
return (_a = tok.match(/(MO|TU|WE|TH|FR|SA|SU)$/)) == null ? void 0 : _a[1];
|
|
1893
|
+
}).filter(Boolean).map((day) => dayMap[day]).filter(Boolean);
|
|
1894
|
+
const nextDayOfWeek = this.findNextValidValue(current.dayOfWeek, targetDays.sort(), (a, b) => a - b);
|
|
1895
|
+
if (nextDayOfWeek) {
|
|
1896
|
+
const delta = (nextDayOfWeek - current.dayOfWeek + 7) % 7;
|
|
1897
|
+
current = current.add({ days: delta }).with({ hour: 0, minute: 0, second: 0 });
|
|
1898
|
+
} else {
|
|
1899
|
+
const delta = (targetDays[0] - current.dayOfWeek + 7) % 7;
|
|
1900
|
+
current = current.add({ days: delta + 7 }).with({ hour: 0, minute: 0, second: 0 });
|
|
1901
|
+
}
|
|
1902
|
+
current = this.applyTimeOverride(current);
|
|
1903
|
+
return current;
|
|
1904
|
+
}
|
|
1905
|
+
switch (this.opts.freq) {
|
|
1906
|
+
case "SECONDLY":
|
|
1907
|
+
case "MINUTELY":
|
|
1908
|
+
current = current.add({ days: 1 }).with({ hour: 0, minute: 0, second: 0 });
|
|
1909
|
+
break;
|
|
1910
|
+
case "HOURLY":
|
|
1911
|
+
current = current.add({ days: 1 }).with({ hour: 0, minute: 0, second: 0 });
|
|
1912
|
+
break;
|
|
1913
|
+
case "DAILY":
|
|
1914
|
+
case "WEEKLY":
|
|
1915
|
+
current = current.add({ months: 1 }).with({ day: 1, hour: 0, minute: 0, second: 0 });
|
|
1916
|
+
break;
|
|
1917
|
+
case "MONTHLY":
|
|
1918
|
+
case "YEARLY":
|
|
1919
|
+
current = current.add({ years: 1 }).with({ month: 1, day: 1, hour: 0, minute: 0, second: 0 });
|
|
1920
|
+
break;
|
|
1921
|
+
}
|
|
1922
|
+
return this.applyTimeOverride(current);
|
|
1923
|
+
}
|
|
1924
|
+
applyBySetPos(list) {
|
|
1925
|
+
const { bySetPos } = this.opts;
|
|
1926
|
+
if (!bySetPos || !bySetPos.length) return list;
|
|
1927
|
+
const sorted = [...list].sort((a, b) => import_temporal_polyfill.Temporal.ZonedDateTime.compare(a, b));
|
|
1928
|
+
const out = [];
|
|
1929
|
+
const len = sorted.length;
|
|
1930
|
+
for (const pos of bySetPos) {
|
|
1931
|
+
const idx = pos > 0 ? pos - 1 : len + pos;
|
|
1932
|
+
if (idx >= 0 && idx < len) out.push(sorted[idx]);
|
|
1933
|
+
}
|
|
1934
|
+
return out.sort((a, b) => import_temporal_polyfill.Temporal.ZonedDateTime.compare(a, b));
|
|
1935
|
+
}
|
|
1936
|
+
isoWeekByDay(sample) {
|
|
1937
|
+
var _a;
|
|
1938
|
+
const dayMap = { MO: 1, TU: 2, WE: 3, TH: 4, FR: 5, SA: 6, SU: 7 };
|
|
1939
|
+
const wkst = dayMap[this.opts.wkst || "MO"];
|
|
1940
|
+
const jan1 = sample.with({ month: 1, day: 1 });
|
|
1941
|
+
const jan4 = sample.with({ month: 1, day: 4 });
|
|
1942
|
+
const delta = (jan4.dayOfWeek - wkst + 7) % 7;
|
|
1943
|
+
const firstWeekStart = jan4.subtract({ days: delta });
|
|
1944
|
+
const isLeapYear = jan1.inLeapYear;
|
|
1945
|
+
const lastWeek = jan1.dayOfWeek === 4 || isLeapYear && jan1.dayOfWeek === 3 ? 53 : 52;
|
|
1946
|
+
const tokens = ((_a = this.opts.byDay) == null ? void 0 : _a.length) ? this.opts.byDay.map((tok) => {
|
|
1947
|
+
var _a2;
|
|
1948
|
+
return (_a2 = tok.match(/(MO|TU|WE|TH|FR|SA|SU)$/)) == null ? void 0 : _a2[1];
|
|
1949
|
+
}) : [Object.entries(dayMap).find(([, d]) => d === this.originalDtstart.dayOfWeek)[0]];
|
|
1950
|
+
return { lastWeek, firstWeekStart, tokens };
|
|
1951
|
+
}
|
|
1952
|
+
/**
|
|
1953
|
+
* Generate occurrences for a specific week number in a given year
|
|
1954
|
+
*/
|
|
1955
|
+
generateOccurrencesForWeekInYear(year, weekNo) {
|
|
1956
|
+
const occs = [];
|
|
1957
|
+
const sample = this.originalDtstart.with({ year, month: 1, day: 1 });
|
|
1958
|
+
const { lastWeek, firstWeekStart, tokens } = this.isoWeekByDay(sample);
|
|
1959
|
+
if (weekNo > 0 && weekNo > lastWeek || weekNo < 0 && -weekNo > lastWeek) {
|
|
1960
|
+
return occs;
|
|
1961
|
+
}
|
|
1962
|
+
const weekIndex = weekNo > 0 ? weekNo - 1 : lastWeek + weekNo;
|
|
1963
|
+
const weekStart = firstWeekStart.add({ weeks: weekIndex });
|
|
1964
|
+
occs.push(...this.addByDay(tokens, weekStart));
|
|
1965
|
+
return occs.sort((a, b) => import_temporal_polyfill.Temporal.ZonedDateTime.compare(a, b));
|
|
1966
|
+
}
|
|
1967
|
+
// ===== RSCALE (non-Gregorian) support: Chinese and Hebrew =====
|
|
1968
|
+
getRscaleCalendarId() {
|
|
1969
|
+
var _a;
|
|
1970
|
+
const map = {
|
|
1971
|
+
GREGORIAN: "gregory",
|
|
1972
|
+
CHINESE: "chinese",
|
|
1973
|
+
HEBREW: "hebrew",
|
|
1974
|
+
INDIAN: "indian"
|
|
1975
|
+
};
|
|
1976
|
+
const r = ((_a = this.opts.rscale) == null ? void 0 : _a.toUpperCase()) || "";
|
|
1977
|
+
return map[r] || null;
|
|
1978
|
+
}
|
|
1979
|
+
assertRscaleCalendarSupported(calId) {
|
|
1980
|
+
if (calId === "gregory" || calId === "iso8601") return;
|
|
1981
|
+
const cached = _RRuleTemporal.rscaleCalendarSupport[calId];
|
|
1982
|
+
if (cached === true) return;
|
|
1983
|
+
if (cached === false) {
|
|
1984
|
+
throw new Error(`RSCALE=${this.opts.rscale} is not supported by the current Temporal/Intl implementation`);
|
|
1985
|
+
}
|
|
1986
|
+
let supported = true;
|
|
1987
|
+
try {
|
|
1988
|
+
const probe = import_temporal_polyfill.Temporal.ZonedDateTime.from("2000-01-01T00:00:00+00:00[UTC]").withCalendar(calId);
|
|
1989
|
+
void probe.year;
|
|
1990
|
+
void probe.monthCode;
|
|
1991
|
+
void probe.day;
|
|
1992
|
+
} catch (e) {
|
|
1993
|
+
supported = false;
|
|
1994
|
+
}
|
|
1995
|
+
_RRuleTemporal.rscaleCalendarSupport[calId] = supported;
|
|
1996
|
+
if (!supported) {
|
|
1997
|
+
throw new Error(`RSCALE=${this.opts.rscale} is not supported by the current Temporal/Intl implementation`);
|
|
1998
|
+
}
|
|
1999
|
+
}
|
|
2000
|
+
pad2(n) {
|
|
2001
|
+
return String(n).padStart(2, "0");
|
|
2002
|
+
}
|
|
2003
|
+
monthMatchesToken(monthCode, token) {
|
|
2004
|
+
if (typeof token === "number") {
|
|
2005
|
+
return monthCode === `M${this.pad2(token)}`;
|
|
2006
|
+
}
|
|
2007
|
+
if (/^\d+L$/i.test(token)) {
|
|
2008
|
+
const n = parseInt(token, 10);
|
|
2009
|
+
return monthCode === `M${this.pad2(n)}L`;
|
|
2010
|
+
}
|
|
2011
|
+
return false;
|
|
2012
|
+
}
|
|
2013
|
+
monthsOfYear(calId, year) {
|
|
2014
|
+
const out = [];
|
|
2015
|
+
for (let m = 1; m <= 20; m++) {
|
|
2016
|
+
try {
|
|
2017
|
+
const d = import_temporal_polyfill.Temporal.PlainDate.from({ calendar: calId, year, month: m, day: 1 });
|
|
2018
|
+
out.push(d);
|
|
2019
|
+
} catch (e) {
|
|
2020
|
+
break;
|
|
2021
|
+
}
|
|
2022
|
+
}
|
|
2023
|
+
return out;
|
|
2024
|
+
}
|
|
2025
|
+
startOfYear(calId, year) {
|
|
2026
|
+
return import_temporal_polyfill.Temporal.PlainDate.from({ calendar: calId, year, month: 1, day: 1 });
|
|
2027
|
+
}
|
|
2028
|
+
endOfYear(calId, year) {
|
|
2029
|
+
return this.startOfYear(calId, year + 1).subtract({ days: 1 });
|
|
2030
|
+
}
|
|
2031
|
+
rscaleFirstWeekStart(calId, year, wkst) {
|
|
2032
|
+
const jan4 = import_temporal_polyfill.Temporal.PlainDate.from({ calendar: calId, year, month: 1, day: 4 });
|
|
2033
|
+
const delta = (jan4.dayOfWeek - wkst + 7) % 7;
|
|
2034
|
+
return jan4.subtract({ days: delta });
|
|
2035
|
+
}
|
|
2036
|
+
rscaleLastWeekCount(calId, year, wkst) {
|
|
2037
|
+
const firstWeekStart = this.rscaleFirstWeekStart(calId, year, wkst);
|
|
2038
|
+
const lastDay = this.endOfYear(calId, year);
|
|
2039
|
+
const diffDays = lastDay.since(firstWeekStart).days;
|
|
2040
|
+
return Math.floor(diffDays / 7) + 1;
|
|
2041
|
+
}
|
|
2042
|
+
lastDayOfMonth(pd) {
|
|
2043
|
+
return pd.with({ day: 1 }).add({ months: 1 }).subtract({ days: 1 }).day;
|
|
2044
|
+
}
|
|
2045
|
+
buildZdtFromPlainDate(pd) {
|
|
2046
|
+
const t = this.originalDtstart;
|
|
2047
|
+
const pdt = import_temporal_polyfill.Temporal.PlainDateTime.from({
|
|
2048
|
+
calendar: pd.calendarId,
|
|
2049
|
+
year: pd.year,
|
|
2050
|
+
month: pd.month,
|
|
2051
|
+
day: pd.day,
|
|
2052
|
+
hour: t.hour,
|
|
2053
|
+
minute: t.minute,
|
|
2054
|
+
second: t.second
|
|
2055
|
+
});
|
|
2056
|
+
return pdt.toZonedDateTime(this.tzid);
|
|
2057
|
+
}
|
|
2058
|
+
rscaleMatchesByYearDay(calId, pd) {
|
|
2059
|
+
const list = this.opts.byYearDay;
|
|
2060
|
+
if (!list || list.length === 0) return true;
|
|
2061
|
+
const last = this.endOfYear(calId, pd.year).dayOfYear;
|
|
2062
|
+
return list.some((d) => d > 0 ? pd.dayOfYear === d : pd.dayOfYear === last + d + 1);
|
|
2063
|
+
}
|
|
2064
|
+
rscaleMatchesByWeekNo(calId, pd) {
|
|
2065
|
+
const list = this.opts.byWeekNo;
|
|
2066
|
+
if (!list || list.length === 0) return true;
|
|
2067
|
+
const dayMap = { MO: 1, TU: 2, WE: 3, TH: 4, FR: 5, SA: 6, SU: 7 };
|
|
2068
|
+
const wkst = dayMap[this.opts.wkst || "MO"];
|
|
2069
|
+
const weekStart = pd.subtract({ days: (pd.dayOfWeek - wkst + 7) % 7 });
|
|
2070
|
+
const thursday = weekStart.add({ days: (4 - wkst + 7) % 7 });
|
|
2071
|
+
const weekYear = thursday.year;
|
|
2072
|
+
const firstStart = this.rscaleFirstWeekStart(calId, weekYear, wkst);
|
|
2073
|
+
const lastWeek = this.rscaleLastWeekCount(calId, weekYear, wkst);
|
|
2074
|
+
const idx = Math.floor(pd.since(firstStart).days / 7) + 1;
|
|
2075
|
+
return list.some((wn) => wn > 0 ? idx === wn : idx === lastWeek + wn + 1);
|
|
2076
|
+
}
|
|
2077
|
+
rscaleMatchesByMonth(calId, pd) {
|
|
2078
|
+
const tokens = this.opts.byMonth;
|
|
2079
|
+
if (!tokens || tokens.length === 0) return true;
|
|
2080
|
+
return tokens.some((tok) => this.monthMatchesToken(pd.monthCode, tok));
|
|
2081
|
+
}
|
|
2082
|
+
rscaleMatchesByMonthDay(pd) {
|
|
2083
|
+
const list = this.opts.byMonthDay;
|
|
2084
|
+
if (!list || list.length === 0) return true;
|
|
2085
|
+
const last = pd.with({ day: 1 }).add({ months: 1 }).subtract({ days: 1 }).day;
|
|
2086
|
+
const value = pd.day;
|
|
2087
|
+
return list.some((d) => d > 0 ? value === d : value === last + d + 1);
|
|
2088
|
+
}
|
|
2089
|
+
rscaleMatchesByDayBasic(pd) {
|
|
2090
|
+
const byDay = this.opts.byDay;
|
|
2091
|
+
if (!byDay || byDay.length === 0) return true;
|
|
2092
|
+
const dayMap = { MO: 1, TU: 2, WE: 3, TH: 4, FR: 5, SA: 6, SU: 7 };
|
|
2093
|
+
const tokens = byDay.map((tok) => {
|
|
2094
|
+
var _a;
|
|
2095
|
+
return (_a = tok.match(/^(?:[+-]?\d{1,2})?(MO|TU|WE|TH|FR|SA|SU)$/)) == null ? void 0 : _a[1];
|
|
2096
|
+
}).filter((x) => !!x);
|
|
2097
|
+
if (tokens.length === 0) return true;
|
|
2098
|
+
return tokens.some((wd) => dayMap[wd] === pd.dayOfWeek);
|
|
2099
|
+
}
|
|
2100
|
+
rscaleDateMatches(calId, pd) {
|
|
2101
|
+
return this.rscaleMatchesByMonth(calId, pd) && this.rscaleMatchesByYearDay(calId, pd) && this.rscaleMatchesByWeekNo(calId, pd) && this.rscaleMatchesByMonthDay(pd) && this.rscaleMatchesByDayBasic(pd);
|
|
2102
|
+
}
|
|
2103
|
+
applySkipForDay(calId, year, monthStart, targetDay) {
|
|
2104
|
+
const last = this.lastDayOfMonth(monthStart);
|
|
2105
|
+
const skip = this.opts.skip || "OMIT";
|
|
2106
|
+
if (targetDay >= 1 && targetDay <= last) {
|
|
2107
|
+
return monthStart.with({ day: targetDay });
|
|
2108
|
+
}
|
|
2109
|
+
if (skip === "BACKWARD") {
|
|
2110
|
+
return monthStart.with({ day: last });
|
|
2111
|
+
}
|
|
2112
|
+
if (skip === "FORWARD") {
|
|
2113
|
+
const nextMonthStart = monthStart.add({ months: 1 });
|
|
2114
|
+
return nextMonthStart.with({ day: 1 });
|
|
2115
|
+
}
|
|
2116
|
+
return null;
|
|
2117
|
+
}
|
|
2118
|
+
generateMonthlyOccurrencesRscale(calId, year, monthStart) {
|
|
2119
|
+
const occs = [];
|
|
2120
|
+
const byMonthDay = this.opts.byMonthDay;
|
|
2121
|
+
const byDay = this.opts.byDay;
|
|
2122
|
+
if (!byDay && !byMonthDay) {
|
|
2123
|
+
const targetDay = this.originalDtstart.withCalendar(calId).day;
|
|
2124
|
+
const pd = this.applySkipForDay(calId, year, monthStart, targetDay);
|
|
2125
|
+
if (pd) occs.push(this.buildZdtFromPlainDate(pd));
|
|
2126
|
+
return occs;
|
|
2127
|
+
}
|
|
2128
|
+
const addZ = (pd) => {
|
|
2129
|
+
occs.push(this.buildZdtFromPlainDate(pd));
|
|
2130
|
+
};
|
|
2131
|
+
const last = this.lastDayOfMonth(monthStart);
|
|
2132
|
+
const resolveDay = (d) => d > 0 ? d : last + d + 1;
|
|
2133
|
+
if (byMonthDay && byMonthDay.length > 0) {
|
|
2134
|
+
for (const raw of byMonthDay) {
|
|
2135
|
+
const dayNum = resolveDay(raw);
|
|
2136
|
+
const pd = this.applySkipForDay(calId, year, monthStart, dayNum);
|
|
2137
|
+
if (pd) addZ(pd);
|
|
2138
|
+
}
|
|
2139
|
+
}
|
|
2140
|
+
if (byDay && byDay.length > 0) {
|
|
2141
|
+
const dayMap = { MO: 1, TU: 2, WE: 3, TH: 4, FR: 5, SA: 6, SU: 7 };
|
|
2142
|
+
const buckets = {};
|
|
2143
|
+
let cur = monthStart;
|
|
2144
|
+
while (cur.month === monthStart.month && cur.year === monthStart.year) {
|
|
2145
|
+
const wd = cur.dayOfWeek;
|
|
2146
|
+
(buckets[wd] || (buckets[wd] = [])).push(cur);
|
|
2147
|
+
cur = cur.add({ days: 1 });
|
|
2148
|
+
}
|
|
2149
|
+
for (const tok of byDay) {
|
|
2150
|
+
const m = tok.match(/^([+-]?\d{1,2})?(MO|TU|WE|TH|FR|SA|SU)$/);
|
|
2151
|
+
if (!m) continue;
|
|
2152
|
+
const ord = m[1] ? parseInt(m[1], 10) : 0;
|
|
2153
|
+
const wd = dayMap[m[2]];
|
|
2154
|
+
const list = buckets[wd] || [];
|
|
2155
|
+
if (list.length === 0) continue;
|
|
2156
|
+
if (ord === 0) {
|
|
2157
|
+
for (const pd of list) addZ(pd);
|
|
2158
|
+
} else {
|
|
2159
|
+
const idx = ord > 0 ? ord - 1 : list.length + ord;
|
|
2160
|
+
const pd = list[idx];
|
|
2161
|
+
if (pd) addZ(pd);
|
|
2162
|
+
}
|
|
2163
|
+
}
|
|
2164
|
+
}
|
|
2165
|
+
return this.applyBySetPos(occs).sort((a, b) => import_temporal_polyfill.Temporal.ZonedDateTime.compare(a, b));
|
|
2166
|
+
}
|
|
2167
|
+
_allRscaleNonGregorian(iterator) {
|
|
2168
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
2169
|
+
const calId = this.getRscaleCalendarId();
|
|
2170
|
+
if (!calId) return this._allFallback(iterator);
|
|
2171
|
+
this.assertRscaleCalendarSupported(calId);
|
|
2172
|
+
const dates = [];
|
|
2173
|
+
let iterationCount = 0;
|
|
2174
|
+
const start = this.originalDtstart;
|
|
2175
|
+
const seed = start.withCalendar(calId);
|
|
2176
|
+
const interval = (_a = this.opts.interval) != null ? _a : 1;
|
|
2177
|
+
if (!this.addDtstartIfNeeded(dates, iterator)) {
|
|
2178
|
+
return this.applyCountLimitAndMergeRDates(dates, iterator);
|
|
2179
|
+
}
|
|
2180
|
+
if (this.opts.freq === "YEARLY") {
|
|
2181
|
+
let yearOffset = 0;
|
|
2182
|
+
while (true) {
|
|
2183
|
+
if (++iterationCount > this.maxIterations) {
|
|
2184
|
+
throw new Error(`Maximum iterations (${this.maxIterations}) exceeded in all()`);
|
|
2185
|
+
}
|
|
2186
|
+
const tgtYear = seed.year + yearOffset * interval;
|
|
2187
|
+
let occs = [];
|
|
2188
|
+
const monthsTokens = this.opts.byMonth;
|
|
2189
|
+
const months = this.monthsOfYear(calId, tgtYear);
|
|
2190
|
+
const dayMap = { MO: 1, TU: 2, WE: 3, TH: 4, FR: 5, SA: 6, SU: 7 };
|
|
2191
|
+
const wkst = dayMap[this.opts.wkst || "MO"];
|
|
2192
|
+
if (this.opts.byWeekNo && this.opts.byWeekNo.length > 0) {
|
|
2193
|
+
const firstStart = this.rscaleFirstWeekStart(calId, tgtYear, wkst);
|
|
2194
|
+
const lastWeek = this.rscaleLastWeekCount(calId, tgtYear, wkst);
|
|
2195
|
+
const tokens = ((_b = this.opts.byDay) == null ? void 0 : _b.length) ? this.opts.byDay.map((tok) => {
|
|
2196
|
+
var _a2;
|
|
2197
|
+
return (_a2 = tok.match(/(MO|TU|WE|TH|FR|SA|SU)$/)) == null ? void 0 : _a2[1];
|
|
2198
|
+
}) : [Object.entries(dayMap).find(([, d]) => d === this.originalDtstart.dayOfWeek)[0]];
|
|
2199
|
+
for (const wn of this.opts.byWeekNo) {
|
|
2200
|
+
let idx = wn > 0 ? wn - 1 : lastWeek + wn;
|
|
2201
|
+
if (idx < 0 || idx >= lastWeek) continue;
|
|
2202
|
+
const weekStart = firstStart.add({ weeks: idx });
|
|
2203
|
+
for (const tok of tokens) {
|
|
2204
|
+
const targetDow = dayMap[tok];
|
|
2205
|
+
const pd = weekStart.add({ days: (targetDow - wkst + 7) % 7 });
|
|
2206
|
+
if (monthsTokens && monthsTokens.length > 0) {
|
|
2207
|
+
if (!monthsTokens.some((t) => this.monthMatchesToken(pd.monthCode, t))) continue;
|
|
2208
|
+
}
|
|
2209
|
+
if (this.opts.byYearDay && this.opts.byYearDay.length > 0) {
|
|
2210
|
+
const lastDay = this.endOfYear(calId, tgtYear).dayOfYear;
|
|
2211
|
+
const matches = this.opts.byYearDay.some((d) => {
|
|
2212
|
+
const target = d > 0 ? d : lastDay + d + 1;
|
|
2213
|
+
return pd.dayOfYear === target;
|
|
2214
|
+
});
|
|
2215
|
+
if (!matches) continue;
|
|
2216
|
+
}
|
|
2217
|
+
occs.push(this.buildZdtFromPlainDate(pd));
|
|
2218
|
+
}
|
|
2219
|
+
}
|
|
2220
|
+
} else if (this.opts.byYearDay && this.opts.byYearDay.length > 0) {
|
|
2221
|
+
const startOfYear = this.startOfYear(calId, tgtYear);
|
|
2222
|
+
const lastDay = this.endOfYear(calId, tgtYear).dayOfYear;
|
|
2223
|
+
for (const d of this.opts.byYearDay) {
|
|
2224
|
+
const target = d > 0 ? d : lastDay + d + 1;
|
|
2225
|
+
if (target < 1 || target > lastDay) continue;
|
|
2226
|
+
let pd = startOfYear.add({ days: target - 1 });
|
|
2227
|
+
if (monthsTokens && monthsTokens.length > 0) {
|
|
2228
|
+
if (!monthsTokens.some((t) => this.monthMatchesToken(pd.monthCode, t))) continue;
|
|
2229
|
+
}
|
|
2230
|
+
occs.push(this.buildZdtFromPlainDate(pd));
|
|
2231
|
+
}
|
|
2232
|
+
} else if (!monthsTokens || monthsTokens.length === 0) {
|
|
2233
|
+
try {
|
|
2234
|
+
const pd = import_temporal_polyfill.Temporal.PlainDate.from({
|
|
2235
|
+
calendar: calId,
|
|
2236
|
+
year: tgtYear,
|
|
2237
|
+
monthCode: seed.monthCode,
|
|
2238
|
+
day: seed.day
|
|
2239
|
+
});
|
|
2240
|
+
occs.push(this.buildZdtFromPlainDate(pd));
|
|
2241
|
+
} catch (e) {
|
|
2242
|
+
const skip = this.opts.skip || "OMIT";
|
|
2243
|
+
if (skip === "FORWARD" || skip === "BACKWARD") {
|
|
2244
|
+
const mapped = seed.with({ year: tgtYear });
|
|
2245
|
+
const adjusted = skip === "BACKWARD" ? mapped.subtract({ days: 1 }) : mapped;
|
|
2246
|
+
occs.push(adjusted.withCalendar("iso8601"));
|
|
2247
|
+
}
|
|
2248
|
+
}
|
|
2249
|
+
} else {
|
|
2250
|
+
const monthStarts = months.filter((m) => monthsTokens.some((tok) => this.monthMatchesToken(m.monthCode, tok)));
|
|
2251
|
+
for (const ms of monthStarts) {
|
|
2252
|
+
occs.push(...this.generateMonthlyOccurrencesRscale(calId, tgtYear, ms));
|
|
2253
|
+
}
|
|
2254
|
+
}
|
|
2255
|
+
if (occs.length > 0) {
|
|
2256
|
+
const expanded = occs.flatMap((z) => this.expandByTime(z));
|
|
2257
|
+
const sorted = expanded.sort((a, b) => import_temporal_polyfill.Temporal.ZonedDateTime.compare(a, b));
|
|
2258
|
+
const { shouldBreak } = this.processOccurrences(sorted, dates, start, iterator);
|
|
2259
|
+
if (shouldBreak) break;
|
|
2260
|
+
}
|
|
2261
|
+
yearOffset++;
|
|
2262
|
+
if (this.opts.until && tgtYear > this.opts.until.withCalendar(calId).year) break;
|
|
2263
|
+
}
|
|
2264
|
+
return this.applyCountLimitAndMergeRDates(dates, iterator);
|
|
2265
|
+
}
|
|
2266
|
+
if (this.opts.freq === "WEEKLY") {
|
|
2267
|
+
const dayMap = { MO: 1, TU: 2, WE: 3, TH: 4, FR: 5, SA: 6, SU: 7 };
|
|
2268
|
+
const wkst = dayMap[this.opts.wkst || "MO"];
|
|
2269
|
+
const tokens = ((_c = this.opts.byDay) == null ? void 0 : _c.length) ? this.opts.byDay.map((tok) => {
|
|
2270
|
+
var _a2;
|
|
2271
|
+
return (_a2 = tok.match(/(MO|TU|WE|TH|FR|SA|SU)$/)) == null ? void 0 : _a2[1];
|
|
2272
|
+
}) : [Object.entries(dayMap).find(([, d]) => d === this.originalDtstart.dayOfWeek)[0]];
|
|
2273
|
+
let weekStart = seed.toPlainDate().subtract({ days: (seed.dayOfWeek - wkst + 7) % 7 });
|
|
2274
|
+
while (true) {
|
|
2275
|
+
if (++iterationCount > this.maxIterations) {
|
|
2276
|
+
throw new Error(`Maximum iterations (${this.maxIterations}) exceeded in all()`);
|
|
2277
|
+
}
|
|
2278
|
+
const occs = [];
|
|
2279
|
+
for (const tok of tokens) {
|
|
2280
|
+
const targetDow = dayMap[tok];
|
|
2281
|
+
const pd = weekStart.add({ days: (targetDow - wkst + 7) % 7 });
|
|
2282
|
+
if (import_temporal_polyfill.Temporal.ZonedDateTime.compare(this.buildZdtFromPlainDate(pd), this.originalDtstart) < 0) {
|
|
2283
|
+
continue;
|
|
2284
|
+
}
|
|
2285
|
+
if (this.opts.byWeekNo && this.opts.byWeekNo.length > 0) {
|
|
2286
|
+
const thursday = weekStart.add({ days: (4 - wkst + 7) % 7 });
|
|
2287
|
+
const weekYear = thursday.year;
|
|
2288
|
+
const firstStart = this.rscaleFirstWeekStart(calId, weekYear, wkst);
|
|
2289
|
+
const lastWeek = this.rscaleLastWeekCount(calId, weekYear, wkst);
|
|
2290
|
+
const idx = Math.floor(pd.since(firstStart).days / 7) + 1;
|
|
2291
|
+
const match = this.opts.byWeekNo.some((wn) => wn > 0 ? idx === wn : idx === lastWeek + wn + 1);
|
|
2292
|
+
if (!match) continue;
|
|
2293
|
+
}
|
|
2294
|
+
if (this.opts.byYearDay && this.opts.byYearDay.length > 0) {
|
|
2295
|
+
const last = this.endOfYear(calId, pd.year).dayOfYear;
|
|
2296
|
+
const match = this.opts.byYearDay.some((d) => d > 0 ? pd.dayOfYear === d : pd.dayOfYear === last + d + 1);
|
|
2297
|
+
if (!match) continue;
|
|
2298
|
+
}
|
|
2299
|
+
const monthsTokens = this.opts.byMonth;
|
|
2300
|
+
if (monthsTokens && monthsTokens.length > 0) {
|
|
2301
|
+
if (!monthsTokens.some((t) => this.monthMatchesToken(pd.monthCode, t))) continue;
|
|
2302
|
+
}
|
|
2303
|
+
occs.push(this.buildZdtFromPlainDate(pd));
|
|
2304
|
+
}
|
|
2305
|
+
if (occs.length) {
|
|
2306
|
+
const expanded = occs.flatMap((z) => this.expandByTime(z));
|
|
2307
|
+
const sorted = expanded.sort((a, b) => import_temporal_polyfill.Temporal.ZonedDateTime.compare(a, b));
|
|
2308
|
+
const { shouldBreak } = this.processOccurrences(sorted, dates, start, iterator);
|
|
2309
|
+
if (shouldBreak) return this.applyCountLimitAndMergeRDates(dates, iterator);
|
|
2310
|
+
}
|
|
2311
|
+
weekStart = weekStart.add({ weeks: (_d = this.opts.interval) != null ? _d : 1 });
|
|
2312
|
+
if (this.opts.until) {
|
|
2313
|
+
const z = this.buildZdtFromPlainDate(weekStart.add({ days: 6 }));
|
|
2314
|
+
if (import_temporal_polyfill.Temporal.ZonedDateTime.compare(z, this.opts.until) > 0) break;
|
|
2315
|
+
}
|
|
2316
|
+
}
|
|
2317
|
+
return this.applyCountLimitAndMergeRDates(dates, iterator);
|
|
2318
|
+
}
|
|
2319
|
+
if (this.opts.freq === "MONTHLY") {
|
|
2320
|
+
let cursor = seed.toPlainDate().with({ day: 1 });
|
|
2321
|
+
while (true) {
|
|
2322
|
+
if (++iterationCount > this.maxIterations) {
|
|
2323
|
+
throw new Error(`Maximum iterations (${this.maxIterations}) exceeded in all()`);
|
|
2324
|
+
}
|
|
2325
|
+
const year = cursor.year;
|
|
2326
|
+
const monthStart = cursor;
|
|
2327
|
+
let proceed = true;
|
|
2328
|
+
const monthsTokens = this.opts.byMonth;
|
|
2329
|
+
if (monthsTokens && monthsTokens.length > 0) {
|
|
2330
|
+
proceed = monthsTokens.some((tok) => this.monthMatchesToken(monthStart.monthCode, tok));
|
|
2331
|
+
}
|
|
2332
|
+
if (proceed) {
|
|
2333
|
+
const occs = this.generateMonthlyOccurrencesRscale(calId, year, monthStart);
|
|
2334
|
+
const expanded = occs.flatMap((z) => this.expandByTime(z));
|
|
2335
|
+
const sorted = expanded.sort((a, b) => import_temporal_polyfill.Temporal.ZonedDateTime.compare(a, b));
|
|
2336
|
+
const { shouldBreak } = this.processOccurrences(sorted, dates, start, iterator);
|
|
2337
|
+
if (shouldBreak) break;
|
|
2338
|
+
}
|
|
2339
|
+
cursor = cursor.add({ months: (_e = this.opts.interval) != null ? _e : 1 });
|
|
2340
|
+
if (this.opts.until) {
|
|
2341
|
+
const z = this.buildZdtFromPlainDate(cursor);
|
|
2342
|
+
if (import_temporal_polyfill.Temporal.ZonedDateTime.compare(z, this.opts.until) > 0) break;
|
|
2343
|
+
}
|
|
2344
|
+
}
|
|
2345
|
+
return this.applyCountLimitAndMergeRDates(dates, iterator);
|
|
2346
|
+
}
|
|
2347
|
+
if (this.opts.freq === "DAILY") {
|
|
2348
|
+
let pd = seed.toPlainDate();
|
|
2349
|
+
while (true) {
|
|
2350
|
+
if (++iterationCount > this.maxIterations) {
|
|
2351
|
+
throw new Error(`Maximum iterations (${this.maxIterations}) exceeded in all()`);
|
|
2352
|
+
}
|
|
2353
|
+
if (this.rscaleDateMatches(calId, pd)) {
|
|
2354
|
+
const base = this.buildZdtFromPlainDate(pd);
|
|
2355
|
+
let occs = this.expandByTime(base);
|
|
2356
|
+
occs = this.applyBySetPos(occs);
|
|
2357
|
+
const { shouldBreak } = this.processOccurrences(occs, dates, start, iterator);
|
|
2358
|
+
if (shouldBreak) break;
|
|
2359
|
+
}
|
|
2360
|
+
pd = pd.add({ days: (_f = this.opts.interval) != null ? _f : 1 });
|
|
2361
|
+
if (this.opts.until) {
|
|
2362
|
+
const z = this.buildZdtFromPlainDate(pd);
|
|
2363
|
+
if (import_temporal_polyfill.Temporal.ZonedDateTime.compare(z, this.opts.until) > 0) break;
|
|
2364
|
+
}
|
|
2365
|
+
}
|
|
2366
|
+
return this.applyCountLimitAndMergeRDates(dates, iterator);
|
|
2367
|
+
}
|
|
2368
|
+
if (this.opts.freq === "HOURLY" || this.opts.freq === "MINUTELY") {
|
|
2369
|
+
const unit = this.opts.freq === "HOURLY" ? "hour" : "minute";
|
|
2370
|
+
const unitMs = this.opts.freq === "HOURLY" ? 36e5 : 6e4;
|
|
2371
|
+
const interval2 = (_g = this.opts.interval) != null ? _g : 1;
|
|
2372
|
+
let pd = seed.toPlainDate();
|
|
2373
|
+
const startInstantMs = this.originalDtstart.toInstant().epochMilliseconds;
|
|
2374
|
+
while (true) {
|
|
2375
|
+
if (++iterationCount > this.maxIterations) {
|
|
2376
|
+
throw new Error(`Maximum iterations (${this.maxIterations}) exceeded in all()`);
|
|
2377
|
+
}
|
|
2378
|
+
if (this.rscaleDateMatches(calId, pd)) {
|
|
2379
|
+
const base = this.buildZdtFromPlainDate(pd);
|
|
2380
|
+
let occs = this.expandByTime(base);
|
|
2381
|
+
occs = occs.filter((occ) => {
|
|
2382
|
+
const delta = occ.toInstant().epochMilliseconds - startInstantMs;
|
|
2383
|
+
const steps = Math.floor(delta / unitMs);
|
|
2384
|
+
return steps % interval2 === 0;
|
|
2385
|
+
});
|
|
2386
|
+
const { shouldBreak } = this.processOccurrences(occs, dates, start, iterator);
|
|
2387
|
+
if (shouldBreak) break;
|
|
2388
|
+
}
|
|
2389
|
+
pd = pd.add({ days: 1 });
|
|
2390
|
+
if (this.opts.until) {
|
|
2391
|
+
const z = this.buildZdtFromPlainDate(pd);
|
|
2392
|
+
if (import_temporal_polyfill.Temporal.ZonedDateTime.compare(z, this.opts.until) > 0) break;
|
|
2393
|
+
}
|
|
2394
|
+
}
|
|
2395
|
+
return this.applyCountLimitAndMergeRDates(dates, iterator);
|
|
2396
|
+
}
|
|
2397
|
+
return this._allFallback(iterator);
|
|
2398
|
+
}
|
|
2399
|
+
};
|
|
2400
|
+
_RRuleTemporal.rscaleCalendarSupport = {};
|
|
2401
|
+
var RRuleTemporal = _RRuleTemporal;
|
|
2402
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
2403
|
+
0 && (module.exports = {
|
|
2404
|
+
RRuleTemporal
|
|
2405
|
+
});
|