rrule-temporal
Version: 
Recurrence rule (rrule) processing using Temporal PlainDate/PlainDateTime, with cross-timezone and cross-calendar rrule support
1,264 lines (1,262 loc) • 116 kB
JavaScript
"use strict";
var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
  for (var prop in b || (b = {}))
    if (__hasOwnProp.call(b, prop))
      __defNormalProp(a, prop, b[prop]);
  if (__getOwnPropSymbols)
    for (var prop of __getOwnPropSymbols(b)) {
      if (__propIsEnum.call(b, prop))
        __defNormalProp(a, prop, b[prop]);
    }
  return a;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/totext.ts
var totext_exports = {};
__export(totext_exports, {
  toText: () => toText
});
module.exports = __toCommonJS(totext_exports);
// src/index.ts
var import_polyfill = require("@js-temporal/polyfill");
function unfoldLine(foldedLine) {
  return foldedLine.replace(/\r?\n[ \t]/g, "");
}
function parseIcsDateTime(dateStr, tzid, valueType) {
  const isDate = valueType === "DATE" || !dateStr.includes("T");
  const isoDate = `${dateStr.slice(0, 4)}-${dateStr.slice(4, 6)}-${dateStr.slice(6, 8)}`;
  if (isDate) {
    return import_polyfill.Temporal.PlainDate.from(isoDate).toZonedDateTime({ timeZone: tzid });
  }
  if (dateStr.endsWith("Z")) {
    const iso = `${isoDate}T${dateStr.slice(9, 15)}Z`;
    return import_polyfill.Temporal.Instant.from(iso).toZonedDateTimeISO(tzid || "UTC");
  } else {
    const iso = `${isoDate}T${dateStr.slice(9)}`;
    return import_polyfill.Temporal.PlainDateTime.from(iso).toZonedDateTime(tzid);
  }
}
function parseDateLines(lines, linePrefix, defaultTzid) {
  const dates = [];
  const regex = new RegExp(`^${linePrefix}(?:;VALUE=([^;]+))?(?:;TZID=([^:]+))?:(.+)`, "i");
  for (const line of lines) {
    const match = line.match(regex);
    if (match) {
      const [, valueType, tzid, dateValuesStr] = match;
      const timezone = tzid || defaultTzid;
      const dateValues = dateValuesStr.split(",");
      dates.push(...dateValues.map((dateValue) => parseIcsDateTime(dateValue, timezone, valueType)));
    }
  }
  return dates;
}
function parseNumberArray(val, sort = false) {
  const arr = val.split(",").map((n) => parseInt(n, 10));
  if (sort) {
    return arr.sort((a, b) => a - b);
  }
  return arr;
}
function parseByMonthArray(val) {
  return val.split(",").map((tok) => {
    const t = tok.trim();
    if (/^\d+L$/i.test(t)) return t.toUpperCase();
    const n = parseInt(t, 10);
    return Number.isFinite(n) ? n : t;
  });
}
function parseRRuleString(input, targetTimezone) {
  var _a;
  const unfoldedInput = unfoldLine(input).trim();
  let dtstart;
  let tzid = "UTC";
  let rruleLine;
  let exDate = [];
  let rDate = [];
  if (/^DTSTART/im.test(unfoldedInput)) {
    const lines = unfoldedInput.split(/\s+/);
    const dtLine = lines.find((line) => line.match(/^DTSTART/i));
    const rrLine = lines.find((line) => line.match(/^RRULE:/i));
    const exLines = lines.filter((line) => line.match(/^EXDATE/i));
    const rLines = lines.filter((line) => line.match(/^RDATE/i));
    const dtMatch = dtLine.match(/DTSTART(?:;VALUE=([^;]+))?(?:;TZID=([^:]+))?:(.+)/i);
    if (!dtMatch) throw new Error("Invalid DTSTART in ICS snippet");
    const [, valueType, dtTzid, dtValue] = dtMatch;
    tzid = (_a = dtTzid != null ? dtTzid : targetTimezone) != null ? _a : tzid;
    dtstart = parseIcsDateTime(dtValue, tzid, valueType);
    rruleLine = rrLine;
    exDate = parseDateLines(exLines, "EXDATE", tzid);
    rDate = parseDateLines(rLines, "RDATE", tzid);
  } else {
    throw new Error("dtstart required when parsing RRULE alone");
  }
  const parts = rruleLine ? rruleLine.replace(/^RRULE:/i, "").split(";") : [];
  const opts = {
    dtstart,
    tzid,
    exDate: exDate.length > 0 ? exDate : void 0,
    rDate: rDate.length > 0 ? rDate : void 0
  };
  let pendingSkip;
  for (const part of parts) {
    const [key, val] = part.split("=");
    if (!key) continue;
    switch (key.toUpperCase()) {
      case "RSCALE":
        if (val) {
          opts.rscale = val.toUpperCase();
          if (pendingSkip && !opts.skip) {
            opts.skip = pendingSkip;
            pendingSkip = void 0;
          }
        }
        break;
      case "SKIP": {
        const v = (val || "").toUpperCase();
        if (!["OMIT", "BACKWARD", "FORWARD"].includes(v)) {
          throw new Error(`Invalid SKIP value: ${val}`);
        }
        if (opts.rscale) {
          opts.skip = v;
        } else {
          pendingSkip = v;
        }
        break;
      }
      case "FREQ":
        opts.freq = val.toUpperCase();
        break;
      case "INTERVAL":
        opts.interval = parseInt(val, 10);
        break;
      case "COUNT":
        opts.count = parseInt(val, 10);
        break;
      case "UNTIL": {
        opts.until = parseIcsDateTime(val, tzid || "UTC");
        if (!val.endsWith("Z") && tzid !== "UTC") {
          throw new Error("UNTIL rule part MUST always be specified as a date with UTC time");
        }
        break;
      }
      case "BYHOUR":
        opts.byHour = parseNumberArray(val, true);
        break;
      case "BYMINUTE":
        opts.byMinute = parseNumberArray(val, true);
        break;
      case "BYSECOND":
        opts.bySecond = parseNumberArray(val, true);
        break;
      case "BYDAY":
        opts.byDay = val.split(",");
        break;
      case "BYMONTH":
        opts.byMonth = parseByMonthArray(val);
        break;
      case "BYMONTHDAY":
        opts.byMonthDay = parseNumberArray(val);
        break;
      case "BYYEARDAY":
        opts.byYearDay = parseNumberArray(val);
        break;
      case "BYWEEKNO":
        opts.byWeekNo = parseNumberArray(val);
        break;
      case "BYSETPOS":
        opts.bySetPos = parseNumberArray(val);
        break;
      case "WKST":
        opts.wkst = val;
        break;
    }
  }
  if (pendingSkip && !opts.rscale) {
    throw new Error("SKIP MUST NOT be present unless RSCALE is present");
  }
  if (pendingSkip && opts.rscale && !opts.skip) {
    opts.skip = pendingSkip;
  }
  return opts;
}
var RRuleTemporal = class _RRuleTemporal {
  constructor(params) {
    var _a, _b, _c, _d, _e;
    let manual;
    if ("rruleString" in params) {
      const parsed = parseRRuleString(params.rruleString, params.tzid);
      this.tzid = (_b = (_a = parsed.tzid) != null ? _a : params.tzid) != null ? _b : "UTC";
      this.originalDtstart = parsed.dtstart;
      manual = __spreadProps(__spreadValues({}, parsed), {
        maxIterations: params.maxIterations,
        includeDtstart: params.includeDtstart,
        tzid: this.tzid
      });
    } else {
      manual = __spreadValues({}, params);
      if (typeof manual.dtstart === "string") {
        throw new Error("Manual dtstart must be a ZonedDateTime");
      }
      manual.tzid = manual.tzid || manual.dtstart.timeZoneId;
      this.tzid = manual.tzid;
      this.originalDtstart = manual.dtstart;
    }
    if (!manual.freq) throw new Error("RRULE must include FREQ");
    manual.interval = (_c = manual.interval) != null ? _c : 1;
    if (manual.interval <= 0) {
      throw new Error("Cannot create RRule: interval must be greater than 0");
    }
    if (manual.until && !(manual.until instanceof import_polyfill.Temporal.ZonedDateTime)) {
      throw new Error("Manual until must be a ZonedDateTime");
    }
    this.opts = this.sanitizeOpts(manual);
    this.maxIterations = (_d = manual.maxIterations) != null ? _d : 1e4;
    this.includeDtstart = (_e = manual.includeDtstart) != null ? _e : false;
  }
  sanitizeNumericArray(arr, min, max, allowZero = false, sort = false) {
    if (!arr) return void 0;
    const sanitized = arr.filter((n) => Number.isInteger(n) && n >= min && n <= max && (allowZero || n !== 0));
    if (sanitized.length === 0) return void 0;
    return sort ? sanitized.sort((a, b) => a - b) : sanitized;
  }
  sanitizeByDay(byDay) {
    const validDay = /^([+-]?\d{1,2})?(MO|TU|WE|TH|FR|SA|SU)$/;
    const days = (byDay != null ? byDay : []).filter((day) => day && typeof day === "string");
    for (const day of days) {
      const match = day.match(validDay);
      if (!match) {
        throw new Error(`Invalid BYDAY value: ${day}`);
      }
      const ord = match[1];
      if (ord) {
        const ordInt = parseInt(ord, 10);
        if (ordInt === 0) {
          throw new Error(`Invalid BYDAY value: ${day}`);
        }
      }
    }
    return days.length > 0 ? days : void 0;
  }
  sanitizeOpts(opts) {
    var _a;
    opts.byDay = this.sanitizeByDay(opts.byDay);
    if (opts.byMonth) {
      const numeric = opts.byMonth.filter((v) => typeof v === "number");
      const stringy = opts.byMonth.filter((v) => typeof v === "string");
      const sanitizedNum = (_a = this.sanitizeNumericArray(numeric, 1, 12, false, false)) != null ? _a : [];
      const merged = [...sanitizedNum, ...stringy];
      opts.byMonth = merged.length > 0 ? merged : void 0;
    }
    if (opts.rscale && !opts.skip) {
      opts.skip = "OMIT";
    }
    opts.byMonthDay = this.sanitizeNumericArray(opts.byMonthDay, -31, 31, false, false);
    opts.byYearDay = this.sanitizeNumericArray(opts.byYearDay, -366, 366, false, false);
    opts.byWeekNo = this.sanitizeNumericArray(opts.byWeekNo, -53, 53, false, false);
    opts.byHour = this.sanitizeNumericArray(opts.byHour, 0, 23, true, true);
    opts.byMinute = this.sanitizeNumericArray(opts.byMinute, 0, 59, true, true);
    opts.bySecond = this.sanitizeNumericArray(opts.bySecond, 0, 59, true, true);
    if (opts.bySetPos) {
      if (opts.bySetPos.some((p) => p === 0)) {
        throw new Error("bySetPos may not contain 0");
      }
      opts.bySetPos = this.sanitizeNumericArray(opts.bySetPos, -Infinity, Infinity, false, false);
    }
    return opts;
  }
  rawAdvance(zdt) {
    const { freq, interval } = this.opts;
    switch (freq) {
      case "DAILY":
        return zdt.add({ days: interval });
      case "WEEKLY":
        return zdt.add({ weeks: interval });
      case "MONTHLY":
        return zdt.add({ months: interval });
      case "YEARLY":
        return zdt.add({ years: interval });
      case "HOURLY": {
        const originalHour = zdt.hour;
        let next = zdt.add({ hours: interval });
        if (next.hour === originalHour && interval === 1) {
          next = next.add({ hours: interval });
        }
        return next;
      }
      case "MINUTELY":
        return zdt.add({ minutes: interval });
      case "SECONDLY":
        return zdt.add({ seconds: interval });
      default:
        throw new Error(`Unsupported FREQ: ${freq}`);
    }
  }
  /**  Expand one base ZonedDateTime into all BYHOUR × BYMINUTE × BYSECOND
   *  combinations, keeping chronological order. If the options are not
   *  present the original date is returned unchanged.
   */
  expandByTime(base) {
    var _a, _b, _c;
    const hours = (_a = this.opts.byHour) != null ? _a : [base.hour];
    const minutes = (_b = this.opts.byMinute) != null ? _b : [base.minute];
    const seconds = (_c = this.opts.bySecond) != null ? _c : [base.second];
    const out = [];
    for (const h of hours) {
      for (const m of minutes) {
        for (const s of seconds) {
          out.push(base.with({ hour: h, minute: m, second: s }));
        }
      }
    }
    return out.sort((a, b) => import_polyfill.Temporal.ZonedDateTime.compare(a, b));
  }
  nextCandidateSameDate(zdt) {
    const { freq, interval = 1, byHour, byMinute, bySecond } = this.opts;
    if (freq === "HOURLY" && byHour && byHour.length === 1) {
      return this.applyTimeOverride(zdt.add({ days: interval }));
    }
    if (freq === "MINUTELY" && byMinute && byMinute.length === 1) {
      return this.applyTimeOverride(zdt.add({ hours: interval }));
    }
    if (bySecond && bySecond.length > 1) {
      const idx = bySecond.indexOf(zdt.second);
      if (idx !== -1 && idx < bySecond.length - 1) {
        return zdt.with({ second: bySecond[idx + 1] });
      }
    }
    if (freq === "MINUTELY" && byHour && byHour.length > 1 && !byMinute) {
      const next = zdt.add({ minutes: interval });
      if (byHour.includes(next.hour)) {
        return next.with({ second: bySecond ? bySecond[0] : zdt.second });
      }
      const nextHour = byHour.find((h) => h > zdt.hour) || byHour[0];
      if (nextHour && nextHour > zdt.hour) {
        return zdt.with({ hour: nextHour, minute: 0, second: bySecond ? bySecond[0] : zdt.second });
      }
      return this.applyTimeOverride(zdt.add({ days: 1 }));
    }
    if (freq === "SECONDLY") {
      let candidate = zdt;
      if (bySecond && bySecond.length > 0) {
        const nextSecondInList = bySecond.find((s) => s > candidate.second);
        if (nextSecondInList !== void 0) {
          return candidate.with({ second: nextSecondInList });
        }
        candidate = candidate.with({ second: bySecond[0] }).add({ minutes: 1 });
      } else {
        candidate = candidate.add({ seconds: interval });
      }
      if (byMinute && byMinute.length > 0) {
        if (!byMinute.includes(candidate.minute) || candidate.minute === zdt.minute && candidate.second < zdt.second) {
          const nextMinuteInList = byMinute.find((m) => m > candidate.minute);
          if (nextMinuteInList !== void 0) {
            return candidate.with({ minute: nextMinuteInList, second: bySecond ? bySecond[0] : 0 });
          }
          candidate = candidate.with({ minute: byMinute[0], second: bySecond ? bySecond[0] : 0 }).add({ hours: 1 });
        }
      }
      if (byHour && byHour.length > 0) {
        if (!byHour.includes(candidate.hour) || candidate.hour === zdt.hour && candidate.minute < zdt.minute) {
          const nextHourInList = byHour.find((h) => h > candidate.hour);
          if (nextHourInList !== void 0) {
            return candidate.with({
              hour: nextHourInList,
              minute: byMinute ? byMinute[0] : 0,
              second: bySecond ? bySecond[0] : 0
            });
          }
          candidate = candidate.with({ hour: byHour[0], minute: byMinute ? byMinute[0] : 0, second: bySecond ? bySecond[0] : 0 }).add({ days: 1 });
        }
      }
      return candidate;
    }
    if (byMinute && byMinute.length > 1) {
      const idx = byMinute.indexOf(zdt.minute);
      if (idx !== -1 && idx < byMinute.length - 1) {
        return zdt.with({
          minute: byMinute[idx + 1],
          second: bySecond ? bySecond[0] : zdt.second
        });
      }
      if (freq === "MINUTELY" && idx === byMinute.length - 1) {
        if (byHour && byHour.length > 0) {
          const currentHourIdx = byHour.indexOf(zdt.hour);
          if (currentHourIdx !== -1 && currentHourIdx < byHour.length - 1) {
            return zdt.with({
              hour: byHour[currentHourIdx + 1],
              minute: byMinute[0],
              second: bySecond ? bySecond[0] : zdt.second
            });
          } else {
            return this.applyTimeOverride(zdt.add({ days: 1 }));
          }
        }
        return zdt.add({ hours: interval }).with({
          minute: byMinute[0],
          second: bySecond ? bySecond[0] : zdt.second
        });
      }
    }
    if (byHour && byHour.length > 1) {
      const idx = byHour.indexOf(zdt.hour);
      if (idx !== -1 && idx < byHour.length - 1) {
        return zdt.with({
          hour: byHour[idx + 1],
          minute: byMinute ? byMinute[0] : zdt.minute,
          second: bySecond ? bySecond[0] : zdt.second
        });
      }
    }
    if (freq === "HOURLY" && byHour && byHour.length > 1) {
      return this.applyTimeOverride(zdt.add({ days: 1 }));
    }
    return this.applyTimeOverride(this.rawAdvance(zdt));
  }
  applyTimeOverride(zdt) {
    const { byHour, byMinute, bySecond } = this.opts;
    let dt = zdt;
    if (byHour) dt = dt.with({ hour: byHour[0] });
    if (byMinute) dt = dt.with({ minute: byMinute[0] });
    if (bySecond) dt = dt.with({ second: bySecond[0] });
    return dt;
  }
  computeFirst() {
    var _a, _b, _c, _d;
    let zdt = this.originalDtstart;
    if (((_a = this.opts.byWeekNo) == null ? void 0 : _a.length) && ["DAILY", "HOURLY", "MINUTELY", "SECONDLY"].includes(this.opts.freq)) {
      let targetWeek = this.opts.byWeekNo[0];
      let targetYear = zdt.year;
      while (targetYear <= zdt.year + 10) {
        const jan1 = zdt.with({ year: targetYear, month: 1, day: 1 });
        const dec31 = zdt.with({ year: targetYear, month: 12, day: 31 });
        let hasTargetWeek = false;
        if (targetWeek > 0) {
          let maxWeek = 52;
          if (jan1.dayOfWeek === 4 || dec31.dayOfWeek === 4) {
            maxWeek = 53;
          }
          hasTargetWeek = targetWeek <= maxWeek;
        } else {
          let maxWeek = 52;
          if (jan1.dayOfWeek === 4 || dec31.dayOfWeek === 4) {
            maxWeek = 53;
          }
          hasTargetWeek = -targetWeek <= maxWeek;
        }
        if (hasTargetWeek) {
          const firstThursday = jan1.add({ days: (4 - jan1.dayOfWeek + 7) % 7 });
          let weekStart;
          if (targetWeek > 0) {
            weekStart = firstThursday.subtract({ days: 3 }).add({ weeks: targetWeek - 1 });
          } else {
            const lastWeek = jan1.dayOfWeek === 4 || dec31.dayOfWeek === 4 ? 53 : 52;
            weekStart = firstThursday.subtract({ days: 3 }).add({ weeks: lastWeek + targetWeek });
          }
          if ((_b = this.opts.byDay) == null ? void 0 : _b.length) {
            const dayMap = { MO: 1, TU: 2, WE: 3, TH: 4, FR: 5, SA: 6, SU: 7 };
            const targetDays = this.opts.byDay.map((tok) => {
              var _a2;
              return (_a2 = tok.match(/(MO|TU|WE|TH|FR|SA|SU)$/)) == null ? void 0 : _a2[1];
            }).filter(Boolean).map((day) => dayMap[day]).filter(Boolean);
            if (targetDays.length) {
              const candidates = targetDays.map((dayOfWeek) => {
                const delta = (dayOfWeek - weekStart.dayOfWeek + 7) % 7;
                return weekStart.add({ days: delta });
              });
              const firstCandidate = candidates.sort((a, b) => import_polyfill.Temporal.ZonedDateTime.compare(a, b))[0];
              if (firstCandidate && import_polyfill.Temporal.ZonedDateTime.compare(firstCandidate, this.originalDtstart) >= 0) {
                zdt = firstCandidate;
                break;
              }
            }
          } else {
            if (import_polyfill.Temporal.ZonedDateTime.compare(weekStart, this.originalDtstart) >= 0) {
              zdt = weekStart;
              break;
            }
          }
        }
        targetYear++;
      }
    }
    if (((_c = this.opts.byDay) == null ? void 0 : _c.length) && !this.opts.byWeekNo) {
      const dayMap = { MO: 1, TU: 2, WE: 3, TH: 4, FR: 5, SA: 6, SU: 7 };
      const hasOrdinalTokens = this.opts.byDay.some((tok) => /^[+-]?\d/.test(tok));
      if (hasOrdinalTokens && this.opts.byMonth && (this.opts.freq === "MINUTELY" || this.opts.freq === "SECONDLY")) {
        const months = this.opts.byMonth.filter((v) => typeof v === "number").sort((a, b) => a - b);
        let foundFirst = false;
        for (let year = zdt.year; year <= zdt.year + 10 && !foundFirst; year++) {
          for (const month of months) {
            if (year === zdt.year && month < zdt.month) continue;
            const monthSample = zdt.with({ year, month, day: 1 });
            const monthlyOccs = this.generateMonthlyOccurrences(monthSample);
            for (const occ of monthlyOccs) {
              if (import_polyfill.Temporal.ZonedDateTime.compare(occ, zdt) >= 0) {
                if (!occ.toPlainDate().equals(zdt.toPlainDate())) {
                  zdt = this.applyTimeOverride(occ.with({ hour: 0, minute: 0, second: 0 }));
                } else {
                  zdt = occ;
                }
                foundFirst = true;
                break;
              }
            }
            if (foundFirst) break;
          }
        }
      } else {
        let deltas;
        if (["DAILY", "HOURLY", "MINUTELY", "SECONDLY"].includes(this.opts.freq) && this.opts.byDay.every((tok) => /^[A-Z]{2}$/.test(tok))) {
          deltas = this.opts.byDay.map((tok) => (dayMap[tok] - zdt.dayOfWeek + 7) % 7);
        } else {
          deltas = this.opts.byDay.map((tok) => {
            var _a2;
            const wdTok = (_a2 = tok.match(/(MO|TU|WE|TH|FR|SA|SU)$/)) == null ? void 0 : _a2[1];
            return wdTok ? (dayMap[wdTok] - zdt.dayOfWeek + 7) % 7 : null;
          }).filter((d) => d !== null);
        }
        if (deltas.length) {
          zdt = zdt.add({ days: Math.min(...deltas) });
        }
      }
    }
    const { byHour, byMinute, bySecond } = this.opts;
    if (this.opts.freq === "HOURLY" && !byHour && import_polyfill.Temporal.ZonedDateTime.compare(
      zdt.with({ hour: 0, minute: 0, second: 0, microsecond: 0, nanosecond: 0 }),
      this.originalDtstart
    ) > 0) {
      zdt = zdt.with({ hour: 0, minute: 0, second: 0, microsecond: 0, nanosecond: 0 });
    }
    if (this.opts.freq === "MINUTELY" && !byMinute && import_polyfill.Temporal.ZonedDateTime.compare(
      zdt.with({ hour: 0, minute: 0, second: 0, microsecond: 0, nanosecond: 0 }),
      this.originalDtstart
    ) > 0) {
      zdt = zdt.with({ hour: 0, minute: 0, second: 0, microsecond: 0, nanosecond: 0 });
    }
    if (this.opts.freq === "SECONDLY" && ((_d = this.opts.byWeekNo) == null ? void 0 : _d.length) && !bySecond && import_polyfill.Temporal.ZonedDateTime.compare(
      zdt.with({ hour: 0, minute: 0, second: 0, microsecond: 0, nanosecond: 0 }),
      this.originalDtstart
    ) > 0) {
      zdt = zdt.with({ hour: 0, minute: 0, second: 0, microsecond: 0, nanosecond: 0 });
    }
    if (byHour || byMinute || bySecond) {
      const candidates = this.expandByTime(zdt);
      for (const candidate of candidates) {
        if (import_polyfill.Temporal.ZonedDateTime.compare(candidate, this.originalDtstart) >= 0) {
          return candidate;
        }
      }
      zdt = this.applyTimeOverride(this.rawAdvance(zdt));
    }
    return zdt;
  }
  // --- NEW: constraint checks ---
  // 2) Replace your matchesByDay with this:
  matchesByDay(zdt) {
    const { byDay, freq } = this.opts;
    if (!byDay) return true;
    const dayMap = { MO: 1, TU: 2, WE: 3, TH: 4, FR: 5, SA: 6, SU: 7 };
    for (const token of byDay) {
      const m = token.match(/^([+-]?\d{1,2})?(MO|TU|WE|TH|FR|SA|SU)$/);
      if (!m) continue;
      const ord = m[1] ? parseInt(m[1], 10) : 0;
      const weekday = m[2];
      if (!weekday) continue;
      const wd = dayMap[weekday];
      if (freq === "DAILY") {
        if (zdt.dayOfWeek === wd) return true;
        continue;
      }
      if (ord === 0) {
        if (zdt.dayOfWeek === wd) return true;
        continue;
      }
      const month = zdt.month;
      let dt = zdt.with({ day: 1 });
      const candidates = [];
      while (dt.month === month) {
        if (dt.dayOfWeek === wd) candidates.push(dt.day);
        dt = dt.add({ days: 1 });
      }
      const idx = ord > 0 ? ord - 1 : candidates.length + ord;
      if (candidates[idx] === zdt.day) return true;
    }
    return false;
  }
  matchesByMonth(zdt) {
    const { byMonth } = this.opts;
    if (!byMonth) return true;
    const nums = byMonth.filter((v) => typeof v === "number");
    if (nums.length === 0) return true;
    return nums.includes(zdt.month);
  }
  matchesNumericConstraint(value, constraints, maxPositiveValue) {
    return constraints.some((c) => {
      const target = c > 0 ? c : maxPositiveValue + c + 1;
      return value === target;
    });
  }
  matchesByMonthDay(zdt) {
    const { byMonthDay } = this.opts;
    if (!byMonthDay) return true;
    const lastDay = zdt.with({ day: 1 }).add({ months: 1 }).subtract({ days: 1 }).day;
    return this.matchesNumericConstraint(zdt.day, byMonthDay, lastDay);
  }
  matchesByHour(zdt) {
    const { byHour } = this.opts;
    if (!byHour) return true;
    if (byHour.includes(zdt.hour)) {
      return true;
    }
    for (const h of byHour) {
      const intendedTime = zdt.with({ hour: h });
      if (intendedTime.hour === zdt.hour) {
        return true;
      }
    }
    return false;
  }
  matchesByMinute(zdt) {
    const { byMinute } = this.opts;
    if (!byMinute) return true;
    return byMinute.includes(zdt.minute);
  }
  matchesBySecond(zdt) {
    const { bySecond } = this.opts;
    if (!bySecond) return true;
    return bySecond.includes(zdt.second);
  }
  matchesAll(zdt) {
    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);
  }
  matchesByYearDay(zdt) {
    const { byYearDay } = this.opts;
    if (!byYearDay) return true;
    const dayOfYear = zdt.dayOfYear;
    const last = zdt.with({ month: 12, day: 31 }).dayOfYear;
    return this.matchesNumericConstraint(dayOfYear, byYearDay, last);
  }
  getIsoWeekInfo(zdt) {
    const thursday = zdt.add({ days: 4 - zdt.dayOfWeek });
    const year = thursday.year;
    const jan1 = zdt.with({ year, month: 1, day: 1 });
    const firstThursday = jan1.add({ days: (4 - jan1.dayOfWeek + 7) % 7 });
    const diffDays = thursday.toPlainDate().since(firstThursday.toPlainDate()).days;
    const week = Math.floor(diffDays / 7) + 1;
    return { week, year };
  }
  matchesByWeekNo(zdt) {
    const { byWeekNo } = this.opts;
    if (!byWeekNo) return true;
    const { week, year } = this.getIsoWeekInfo(zdt);
    const jan1 = zdt.with({ year, month: 1, day: 1 });
    const isLeapYear = jan1.inLeapYear;
    const lastWeek = jan1.dayOfWeek === 4 || isLeapYear && jan1.dayOfWeek === 3 ? 53 : 52;
    return byWeekNo.some((wn) => {
      if (wn > 0) {
        return week === wn;
      } else {
        return week === lastWeek + wn + 1;
      }
    });
  }
  options() {
    return this.opts;
  }
  addDtstartIfNeeded(dates, iterator) {
    if (this.includeDtstart && !this.matchesAll(this.originalDtstart)) {
      if (iterator && this.isExcluded(this.originalDtstart)) {
        return true;
      }
      if (iterator && !iterator(this.originalDtstart, dates.length)) {
        return false;
      }
      dates.push(this.originalDtstart);
      if (this.shouldBreakForCountLimit(dates.length)) {
        return false;
      }
    }
    return true;
  }
  processOccurrences(occs, dates, start, iterator, extraFilters) {
    let shouldBreak = false;
    for (const occ of occs) {
      if (import_polyfill.Temporal.ZonedDateTime.compare(occ, start) < 0) continue;
      if (this.opts.until && import_polyfill.Temporal.ZonedDateTime.compare(occ, this.opts.until) > 0) {
        shouldBreak = true;
        break;
      }
      if (extraFilters && !extraFilters(occ)) {
        continue;
      }
      if (iterator && this.isExcluded(occ)) {
        continue;
      }
      if (iterator && !iterator(occ, dates.length)) {
        shouldBreak = true;
        break;
      }
      dates.push(occ);
      if (this.shouldBreakForCountLimit(dates.length)) {
        shouldBreak = true;
        break;
      }
    }
    return { shouldBreak };
  }
  /**
   * Returns all occurrences of the rule.
   * @param iterator - An optional callback iterator function that can be used to filter or modify the occurrences.
   * @returns An array of Temporal.ZonedDateTime objects representing all occurrences of the rule.
   */
  _allMonthlyByDayOrMonthDay(iterator) {
    const dates = [];
    let iterationCount = 0;
    const start = this.originalDtstart;
    if (!this.addDtstartIfNeeded(dates, iterator)) {
      return this.applyCountLimitAndMergeRDates(dates, iterator);
    }
    let monthCursor = start.with({ day: 1 });
    while (true) {
      if (++iterationCount > this.maxIterations) {
        throw new Error(`Maximum iterations (${this.maxIterations}) exceeded in all()`);
      }
      let occs = this.generateMonthlyOccurrences(monthCursor);
      occs = this.applyBySetPos(occs);
      if (monthCursor.month === start.month && occs.some((o) => import_polyfill.Temporal.ZonedDateTime.compare(o, start) < 0) && occs.some((o) => import_polyfill.Temporal.ZonedDateTime.compare(o, start) === 0)) {
        monthCursor = monthCursor.add({ months: this.opts.interval });
        continue;
      }
      const { shouldBreak } = this.processOccurrences(occs, dates, start, iterator);
      if (shouldBreak) {
        break;
      }
      monthCursor = monthCursor.add({ months: this.opts.interval });
    }
    return this.applyCountLimitAndMergeRDates(dates, iterator);
  }
  _allWeekly(iterator) {
    var _a;
    const dates = [];
    let iterationCount = 0;
    const start = this.originalDtstart;
    if (!this.addDtstartIfNeeded(dates, iterator)) {
      return this.applyCountLimitAndMergeRDates(dates, iterator);
    }
    const dayMap = { MO: 1, TU: 2, WE: 3, TH: 4, FR: 5, SA: 6, SU: 7 };
    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]];
    const dows = tokens.map((tok) => dayMap[tok.slice(-2)]).filter((d) => d !== void 0).sort((a, b) => a - b);
    const firstWeekDates = dows.map((dw) => {
      const delta = (dw - start.dayOfWeek + 7) % 7;
      return start.add({ days: delta });
    });
    const firstOccurrence = firstWeekDates.reduce((a, b) => import_polyfill.Temporal.ZonedDateTime.compare(a, b) <= 0 ? a : b);
    const wkstDay = (_a = dayMap[this.opts.wkst || "MO"]) != null ? _a : 1;
    const firstOccWeekOffset = (firstOccurrence.dayOfWeek - wkstDay + 7) % 7;
    let weekCursor = firstOccurrence.subtract({ days: firstOccWeekOffset });
    while (true) {
      if (++iterationCount > this.maxIterations) {
        throw new Error(`Maximum iterations (${this.maxIterations}) exceeded in all()`);
      }
      let occs = dows.flatMap((dw) => {
        const delta = (dw - wkstDay + 7) % 7;
        const sameDate = weekCursor.add({ days: delta });
        return this.expandByTime(sameDate);
      }).sort((a, b) => import_polyfill.Temporal.ZonedDateTime.compare(a, b));
      occs = this.applyBySetPos(occs);
      const { shouldBreak } = this.processOccurrences(
        occs,
        dates,
        start,
        iterator,
        (occ) => this.matchesByMonth(occ) && this.matchesByMonthDay(occ)
      );
      if (shouldBreak) {
        break;
      }
      weekCursor = weekCursor.add({ weeks: this.opts.interval });
    }
    return this.applyCountLimitAndMergeRDates(dates, iterator);
  }
  _allMonthlyByMonth(iterator) {
    const dates = [];
    let iterationCount = 0;
    const start = this.originalDtstart;
    if (!this.addDtstartIfNeeded(dates, iterator)) {
      return this.applyCountLimitAndMergeRDates(dates, iterator);
    }
    const months = this.opts.byMonth.filter((v) => typeof v === "number").sort((a, b) => a - b);
    let monthOffset = 0;
    let startMonthIndex = months.findIndex((m) => m >= start.month);
    if (startMonthIndex === -1) {
      startMonthIndex = 0;
      monthOffset = 1;
    }
    while (true) {
      if (++iterationCount > this.maxIterations) {
        throw new Error(`Maximum iterations (${this.maxIterations}) exceeded in all()`);
      }
      const monthIndex = startMonthIndex + monthOffset;
      const targetMonth = months[monthIndex % months.length];
      const yearsToAdd = Math.floor(monthIndex / months.length);
      const candidate = start.with({
        year: start.year + yearsToAdd,
        month: targetMonth
      });
      if (this.opts.until && import_polyfill.Temporal.ZonedDateTime.compare(candidate, this.opts.until) > 0) {
        break;
      }
      if (import_polyfill.Temporal.ZonedDateTime.compare(candidate, start) >= 0) {
        if (iterator && this.isExcluded(candidate)) {
          continue;
        }
        if (iterator && !iterator(candidate, dates.length)) {
          break;
        }
        dates.push(candidate);
        if (this.shouldBreakForCountLimit(dates.length)) {
          break;
        }
      }
      monthOffset++;
    }
    return this.applyCountLimitAndMergeRDates(dates, iterator);
  }
  _allYearlyByMonth(iterator) {
    const dates = [];
    let iterationCount = 0;
    const start = this.originalDtstart;
    if (!this.addDtstartIfNeeded(dates, iterator)) {
      return this.applyCountLimitAndMergeRDates(dates, iterator);
    }
    const months = this.opts.byMonth.filter((v) => typeof v === "number").sort((a, b) => a - b);
    let yearOffset = 0;
    while (true) {
      if (++iterationCount > this.maxIterations) {
        throw new Error(`Maximum iterations (${this.maxIterations}) exceeded in all()`);
      }
      const year = start.year + yearOffset * this.opts.interval;
      for (const month of months) {
        let occ = start.with({ year, month });
        occ = this.applyTimeOverride(occ);
        if (import_polyfill.Temporal.ZonedDateTime.compare(occ, start) < 0) {
          continue;
        }
        if (this.opts.until && import_polyfill.Temporal.ZonedDateTime.compare(occ, this.opts.until) > 0) {
          return this.applyCountLimitAndMergeRDates(dates, iterator);
        }
        if (iterator && this.isExcluded(occ)) {
          continue;
        }
        if (iterator && !iterator(occ, dates.length)) {
          return this.applyCountLimitAndMergeRDates(dates, iterator);
        }
        dates.push(occ);
        if (this.shouldBreakForCountLimit(dates.length)) {
          return this.applyCountLimitAndMergeRDates(dates, iterator);
        }
      }
      yearOffset++;
    }
  }
  _allYearlyComplex(iterator) {
    const dates = [];
    let iterationCount = 0;
    const start = this.originalDtstart;
    if (!this.addDtstartIfNeeded(dates, iterator)) {
      return this.applyCountLimitAndMergeRDates(dates, iterator);
    }
    let yearCursor = start.with({ month: 1, day: 1 });
    while (true) {
      if (++iterationCount > this.maxIterations) {
        throw new Error(`Maximum iterations (${this.maxIterations}) exceeded in all()`);
      }
      const occs = this.generateYearlyOccurrences(yearCursor);
      const uniqueOccs = [];
      if (occs.length > 0) {
        uniqueOccs.push(occs[0]);
        for (let i = 1; i < occs.length; i++) {
          if (import_polyfill.Temporal.ZonedDateTime.compare(occs[i], occs[i - 1]) !== 0) {
            uniqueOccs.push(occs[i]);
          }
        }
      }
      const { shouldBreak } = this.processOccurrences(uniqueOccs, dates, start, iterator);
      if (shouldBreak) {
        break;
      }
      const interval = this.opts.freq === "WEEKLY" ? 1 : this.opts.interval;
      yearCursor = yearCursor.add({ years: interval });
      if (this.opts.freq === "WEEKLY" && this.opts.until && yearCursor.year > this.opts.until.year) {
        break;
      }
    }
    return this.applyCountLimitAndMergeRDates(dates, iterator);
  }
  _allMinutelySecondlyComplex(iterator) {
    const dates = [];
    let iterationCount = 0;
    if (!this.addDtstartIfNeeded(dates, iterator)) {
      return this.applyCountLimitAndMergeRDates(dates, iterator);
    }
    let current = this.computeFirst();
    while (true) {
      if (++iterationCount > this.maxIterations) {
        throw new Error(`Maximum iterations (${this.maxIterations}) exceeded in all()`);
      }
      if (this.opts.until && import_polyfill.Temporal.ZonedDateTime.compare(current, this.opts.until) > 0) {
        break;
      }
      if (this.matchesAll(current)) {
        if (iterator && this.isExcluded(current)) {
          current = this.nextCandidateSameDate(current);
          continue;
        }
        if (iterator && !iterator(current, dates.length)) {
          break;
        }
        dates.push(current);
        if (this.shouldBreakForCountLimit(dates.length)) {
          break;
        }
        current = this.nextCandidateSameDate(current);
      } else {
        current = this.findNextValidDate(current);
      }
    }
    return this.applyCountLimitAndMergeRDates(dates, iterator);
  }
  _allMonthlyByWeekNo(iterator) {
    const dates = [];
    let iterationCount = 0;
    const start = this.originalDtstart;
    if (!this.addDtstartIfNeeded(dates, iterator)) {
      return this.applyCountLimitAndMergeRDates(dates, iterator);
    }
    let current = start;
    const weekNos = [...this.opts.byWeekNo].sort((a, b) => a - b);
    const interval = this.opts.interval;
    let monthsAdvanced = 0;
    let lastYearProcessed = -1;
    outer_loop: while (true) {
      if (this.shouldBreakForCountLimit(dates.length)) {
        break;
      }
      if (++iterationCount > this.maxIterations) {
        throw new Error(`Maximum iterations (${this.maxIterations}) exceeded in all()`);
      }
      const year = current.year;
      if (year !== lastYearProcessed && current.month >= start.month) {
        lastYearProcessed = year;
        for (const weekNo of weekNos) {
          const occs = this.generateOccurrencesForWeekInYear(year, weekNo);
          for (const occ of occs) {
            if (import_polyfill.Temporal.ZonedDateTime.compare(occ, start) >= 0) {
              if (iterator && this.isExcluded(occ)) {
                continue;
              }
              if (iterator && !iterator(occ, dates.length)) {
                break outer_loop;
              }
              dates.push(occ);
              if (this.shouldBreakForCountLimit(dates.length)) {
                break outer_loop;
              }
            }
          }
        }
      }
      monthsAdvanced += interval;
      current = start.add({ months: monthsAdvanced });
      if (this.opts.until && import_polyfill.Temporal.ZonedDateTime.compare(current, this.opts.until) > 0) {
        break;
      }
    }
    return this.applyCountLimitAndMergeRDates(dates, iterator);
  }
  _allMonthlyByYearDay(iterator) {
    const dates = [];
    let iterationCount = 0;
    const start = this.originalDtstart;
    if (!this.addDtstartIfNeeded(dates, iterator)) {
      return this.applyCountLimitAndMergeRDates(dates, iterator);
    }
    let year = start.year;
    const yearDays = [...this.opts.byYearDay].sort((a, b) => a - b);
    const interval = this.opts.interval;
    const startMonthAbs = start.year * 12 + start.month;
    outer_loop: while (true) {
      if (this.shouldBreakForCountLimit(dates.length)) {
        break;
      }
      if (++iterationCount > this.maxIterations) {
        throw new Error(`Maximum iterations (${this.maxIterations}) exceeded in all()`);
      }
      const yearStart = start.with({ year, month: 1, day: 1 });
      const lastDayOfYear = yearStart.with({ month: 12, day: 31 }).dayOfYear;
      for (const yd of yearDays) {
        const dayNum = yd > 0 ? yd : lastDayOfYear + yd + 1;
        if (dayNum <= 0 || dayNum > lastDayOfYear) continue;
        const baseOcc = yearStart.add({ days: dayNum - 1 });
        for (const occ of this.expandByTime(baseOcc)) {
          if (import_polyfill.Temporal.ZonedDateTime.compare(occ, start) < 0) continue;
          if (dates.some((d) => import_polyfill.Temporal.ZonedDateTime.compare(d, occ) === 0)) continue;
          const occMonthAbs = occ.year * 12 + occ.month;
          if ((occMonthAbs - startMonthAbs) % interval !== 0) {
            continue;
          }
          if (!this.matchesByMonth(occ)) {
            continue;
          }
          if (this.opts.until && import_polyfill.Temporal.ZonedDateTime.compare(occ, this.opts.until) > 0) {
            break outer_loop;
          }
          if (iterator && this.isExcluded(occ)) {
            continue;
          }
          if (iterator && !iterator(occ, dates.length)) {
            break outer_loop;
          }
          dates.push(occ);
          if (this.shouldBreakForCountLimit(dates.length)) {
            break outer_loop;
          }
        }
      }
      year++;
      if (this.opts.until && year > this.opts.until.year + 2) {
        break;
      }
      if (!this.opts.until && this.opts.count) {
        const yearsToScan = Math.ceil(this.opts.count / (this.opts.byYearDay.length || 1)) * interval + 5;
        if (year > start.year + yearsToScan) {
          break;
        }
      }
    }
    return this.applyCountLimitAndMergeRDates(dates, iterator);
  }
  _allDailyMinutelyHourlyWithBySetPos(iterator) {
    const dates = [];
    let iterationCount = 0;
    const start = this.originalDtstart;
    if (!this.addDtstartIfNeeded(dates, iterator)) {
      return this.applyCountLimitAndMergeRDates(dates, iterator);
    }
    let cursor;
    let duration;
    switch (this.opts.freq) {
      case "MINUTELY":
        cursor = start.with({ second: 0, microsecond: 0, nanosecond: 0 });
        duration = { minutes: this.opts.interval };
        break;
      case "HOURLY":
        cursor = start.with({ minute: 0, second: 0, microsecond: 0, nanosecond: 0 });
        duration = { hours: this.opts.interval };
        break;
      case "DAILY":
        cursor = start.with({ hour: 0, minute: 0, second: 0, microsecond: 0, nanosecond: 0 });
        duration = { days: this.opts.interval };
        break;
      default:
        return this.applyCountLimitAndMergeRDates(dates, iterator);
    }
    while (true) {
      if (++iterationCount > this.maxIterations) {
        throw new Error(`Maximum iterations (${this.maxIterations}) exceeded in all()`);
      }
      let periodOccs = this.expandByTime(cursor);
      periodOccs = periodOccs.filter((occ) => this.matchesAll(occ));
      periodOccs = this.applyBySetPos(periodOccs);
      const { shouldBreak } = this.processOccurrences(periodOccs, dates, start, iterator);
      if (shouldBreak) {
        break;
      }
      cursor = cursor.add(duration);
      if (this.opts.until && import_polyfill.Temporal.ZonedDateTime.compare(cursor, this.opts.until) > 0) {
        break;
      }
    }
    return this.applyCountLimitAndMergeRDates(dates, iterator);
  }
  _allFallback(iterator) {
    const dates = [];
    let iterationCount = 0;
    let current = this.computeFirst();
    if (this.includeDtstart && import_polyfill.Temporal.ZonedDateTime.compare(current, this.originalDtstart) > 0) {
      if (iterator && this.isExcluded(this.originalDtstart)) {
      } else {
        if (iterator && !iterator(this.originalDtstart, dates.length)) {
          return this.applyCountLimitAndMergeRDates(dates, iterator);
        }
        dates.push(this.originalDtstart);
        if (this.shouldBreakForCountLimit(dates.length)) {
          return this.applyCountLimitAndMergeRDates(dates, iterator);
        }
      }
    }
    while (true) {
      if (++iterationCount > this.maxIterations) {
        throw new Error(`Maximum iterations (${this.maxIterations}) exceeded in all()`);
      }
      if (this.opts.until && import_polyfill.Temporal.ZonedDateTime.compare(current, this.opts.until) > 0) {
        break;
      }
      if (this.matchesAll(current)) {
        if (iterator && this.isExcluded(current)) {
        } else {
          if (iterator && !iterator(current, dates.length)) {
            break;
          }
          dates.push(current);
          if (this.shouldBreakForCountLimit(dates.length)) {
            break;
          }
        }
      }
      current = this.nextCandidateSameDate(current);
    }
    return this.applyCountLimitAndMergeRDates(dates, iterator);
  }
  /**
   * Returns all occurrences of the rule.
   * @param iterator - An optional callback iterator function that can be used to filter or modify the occurrences.
   * @returns An array of Temporal.ZonedDateTime objects representing all occurrences of the rule.
   */
  all(iterator) {
    if (this.opts.rscale && ["CHINESE", "HEBREW", "INDIAN"].includes(this.opts.rscale)) {
      if (["YEARLY", "MONTHLY", "WEEKLY"].includes(this.opts.freq) || !!this.opts.byYearDay || !!this.opts.byWeekNo || this.opts.byMonthDay && this.opts.byMonthDay.length > 0) {
        return this._allRscaleNonGregorian(iterator);
      }
    }
    if (this.opts.byWeekNo && this.opts.byYearDay) {
      const yearStart = this.originalDtstart.with({ month: 1, day: 1, hour: 0, minute: 0, second: 0, millisecond: 0 });
      const yearDays = this.opts.byYearDay.map((yd) => {
        const lastDayOfYear = yearStart.with({ month: 12, day: 31 }).dayOfYear;
        return yd > 0 ? yd : lastDayOfYear + yd + 1;
      });
      let possibleDate = false;
      for (const yd of yearDays) {
        const date = yearStart.add({ days: yd - 1 });
        if (this.matchesByWeekNo(date)) {
          possibleDate = true;
          break;
        }
      }
      if (!possibleDate) {
        return [];
      }
    }
    if (!this.opts.count && !this.opts.until && !iterator) {
      throw new Error("all() requires iterator when no COUNT/UNTIL");
    }
    if (this.opts.freq === "MONTHLY" && (this.opts.byDay || this.opts.byMonthDay) && !this.opts.byWeekNo) {
      return this._allMonthlyByDayOrMonthDay(iterator);
    }
    if (this.opts.freq === "WEEKLY" && !(this.opts.byYearDay && this.opts.byYearDay.length > 0) && !(this.opts.byWeekNo && this.opts.byWeekNo.length > 0)) {
      return this._allWeekly(iterator);
    }
    if (this.opts.freq === "MONTHLY" && this.opts.byMonth && !this.opts.byDay && !this.opts.byMonthDay && !this.opts.byYearDay) {
      return this._allMonthlyByMonth(iterator);
    }
    if (this.opts.freq === "YEARLY" && this.opts.byMonth && !this.opts.byDay && !this.opts.byMonthDay && !this.opts.byYearDay && !this.opts.byWeekNo) {
      return this._allYearlyByMonth(iterator);
    }
    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) {
      return this._allYearlyComplex(iterator);
    }
    if ((this.opts.freq === "MINUTELY" || this.opts.freq === "SECONDLY") && (this.opts.byMonth || this.opts.byWeekNo || this.opts.byYearDay || this.opts.byMonthDay || this.opts.byDay)) {
      return this._allMinutelySecondlyComplex(iterator);
    }
    if (this.opts.freq === "MONTHLY" && this.opts.byWeekNo && this.opts.byWeekNo.length > 0) {
      return this._allMonthlyByWeekNo(iterator);
    }
    if (this.opts.freq === "MONTHLY" && this.opts.byYearDay && this.opts.byYearDay.length > 0 && !this.opts.byDay && !this.opts.byMonthDay) {
      return this._allMonthlyByYearDay(iterator);
    }
    if (this.opts.rscale && this.opts.freq === "MONTHLY" && !this.opts.byDay && !this.opts.byMonthDay && !this.opts.byWeekNo && !this.opts.byYearDay) {
      return this._allMonthlyRscaleSimple(iterator);
    }
    if ((this.opts.freq === "MINUTELY" || this.opts.freq === "HOURLY" || this.opts.freq === "DAILY") && this.opts.bySetPos) {
      return this._allDailyMinutelyHourlyWithBySetPos(iterator);
    }
    return this._allFallback(iterator);
  }
  /**
   * RFC 7529: RSCALE present, simple monthly iteration with SKIP behavior.
   * Handles month-to-month stepping from DTSTART's year/month aiming for DTSTART's day-of-month.
   * Applies SKIP=OMIT (skip invalid months), BACKWARD (clamp to last day), FORWARD (first day of next month).
   */
  _allMonthlyRscaleSimple(iterator) {
    var _a;
    const dates = [];
    let iterationCount = 0;
    const start = this.originalDtstart;
    const interval = (_a = this.opts.interval) != null ? _a : 1;
    const targetDom = start.day;
    if (!this.addDtstartIfNeeded(dates, iterator)) {
      return this.applyCountLimitAndMergeRDates(dates, iterator);
    }
    let cursor = start.with({ day: 1 });
    while (true) {
      if (++iterationCount > this.maxIterations) {
        throw new Error(`Maximum iterations (${this.maxIterations}) exceeded in all()`);
      }
      const lastDay = cursor.add({ months: 1 }).subtract({ days: 1 }).day;
      let occ = null;
      if (targetDom <= lastDay) {
        occ = cursor.with({ day: targetDom });
      } else {
        const skip = this.opts.skip || "OMIT";
        if (skip === "BACKWARD") {
          occ = cursor.with({ day: lastDay });
        } else if (skip === "FORWARD") {
          occ = cursor.add({ months: 1 }).with({ day: 1 });
        } else {
          occ = null;
        }
      }
      if (occ) {
        occ = occ.with({ hour: start.hour, minute: start.minute, second: start.second });
        if (!(iterator && this.isExcluded(occ))) {
          if (import_polyfill.Temporal.ZonedDateTime.compare(occ, start) >= 0) {
            if (!iterator || iterator(occ, dates.length)) {
              dates.push(occ);
              if (this.shouldBreakForCountLimit(dates.length)) break;
            } else {
              break;
            }
          }
        }
      }
      cursor = cursor.add({ months: interval });
      if (this.opts.until && import_polyfill.Temporal.ZonedDateTime.compare(cursor, this.opts.until) > 0) {
        break;
      }
    }
    return this.applyCountLimitAndMergeRDates(dates, iterator);
  }
  /**
   * Converts rDate e