4.0 KiB
recurrence-generate
Purpose
recurrence-generate provides the internal generator functions that produce infinite sequences of candidate dates for each recurrence frequency supported by @suaveplan/datetime. Each generator yields dates strictly after a given from anchor, and the generateCandidates dispatcher routes to the correct generator based on RecurrenceRule.freq.
This module is an internal implementation detail. Public callers should use expandRecurrence and nextOccurrence from recurrence.ts.
Features
generateDaily— daily step with optionalBYDAYweekday filtergenerateWeekly— weekly step, either plain (same weekday) or withBYDAYmulti-day selectiongenerateMonthly— monthly step supportingBYMONTHDAY,BYDAY, or plain monthly recurrencegenerateYearly— yearly step supportingBYMONTHDAY,BYDAY, or plain yearly recurrencegenerateCandidates— dispatcher that routes to the correct generator fromRecurrenceRule.freq- All generators are infinite; termination is enforced by callers (
count/until/AbortSignal)
Usage: Basic Example
import { generateCandidates } from "./recurrence-generate.js";
const rule = { freq: "daily" as const, count: 5 };
const from = new Date(2024, 0, 1);
const gen = generateCandidates(rule, from);
for (let i = 0; i < 5; i++) {
console.log(gen.next().value?.toDateString());
}
// Tue Jan 02 2024 … Sat Jan 06 2024
Usage: Advanced Example
import { generateCandidates } from "./recurrence-generate.js";
// Monthly with BYMONTHDAY — yields the 15th of each month
const rule = {
freq: "monthly" as const,
byMonthDay: [15],
};
const from = new Date(2024, 0, 1);
const gen = generateCandidates(rule, from);
const first = gen.next().value!;
console.log(first.toDateString()); // Mon Jan 15 2024
const second = gen.next().value!;
console.log(second.toDateString()); // Thu Feb 15 2024
// Weekly with BYDAY — yields Mon/Wed/Fri
const weeklyRule = {
freq: "weekly" as const,
byDay: [1, 3, 5] as const,
};
const weeklyGen = generateCandidates(weeklyRule, new Date(2024, 2, 11));
console.log(weeklyGen.next().value?.getDay()); // 3 (Wed Mar 13)
API Reference
generateCandidates(rule: RecurrenceRule, from: Date): Generator<Date>
Unified dispatcher. Routes to the frequency-specific generator based on rule.freq. All yielded dates are strictly after from.
generateDaily(rule, from, interval): Generator<Date>
Steps interval days at a time. If rule.byDay is set, only yields dates whose getDay() is in the list.
generateWeekly(rule, from, interval): Generator<Date>
If rule.byDay is set: anchors to the Sunday of the current week, then emits the specified weekdays in sorted order each interval * 7 days. Without byDay: yields the same weekday every interval * 7 days.
generateMonthly(rule, from, interval): Generator<Date>
Three modes:
byMonthDay— emits the specified day-of-month values (sorted) in each month, skipping months where a day exceedsdaysInMonth.byDay— scans each month and emits all days matching the weekday list.- Plain — yields the same day-of-month each
intervalmonths usingaddMonthsclamping.
generateYearly(rule, from, interval): Generator<Date>
Three modes:
byMonthDay— emits specified day-of-month values in each year.byDay— advances one day at a time from the year anchor, yielding matching weekdays.- Plain — yields the same date each
intervalyears usingaddYears.
Implementation Notes
All generators are implemented as native ES Generator functions (function*) to enable lazy evaluation. They produce an infinite sequence; the caller (expandRecurrence, nextOccurrence) is responsible for applying count, until, and AbortSignal termination conditions.
The generateWeekly with BYDAY mode anchors to the start of the week (Sunday) on the first iteration, which means it may emit dates in the current week before advancing. Dates before or equal to from are filtered out with a candidate > from guard.