import { type Maybe, type TimezoneString } from '@dereekb/util'; import { RRule, type Options } from './rrule.interop'; import { type CalendarDate, DateSet, type DateRange, type DateRangeParams } from '../date'; import { type BaseDateAsUTC, DateTimezoneUtcNormalInstance } from '../date/date.timezone'; import { DateRRule } from './date.rrule.extension'; import { type RRuleLines, type RRuleStringLineSet, type RRuleStringSetSeparation } from './date.rrule.parse'; /** * Alias emphasizing that dates passed to the RRule library must be expressed * in UTC, since RRule internally treats all timestamps as UTC. */ export type RRuleBaseDateAsUTC = BaseDateAsUTC; /** * Options controlling which portion of a recurrence rule is expanded into * concrete dates. Provide either a resolved {@link DateRange} or * {@link DateRangeParams} to limit the expansion window. */ export interface DateRRuleExpansionOptions { /** * Start/End Dates to get the range between. */ range?: DateRange; /** * Optional DateRangeParams to derive the start/end from. */ rangeParams?: DateRangeParams; } /** * Parameters for constructing a {@link DateRRuleInstance}. Exactly one of * `rruleLines` or `rruleStringLineSet` must be provided. */ export interface MakeDateRRuleInstance { /** * Lines string to build an RRule from. */ rruleLines?: RRuleLines; /** * Line set to build an RRule from. */ rruleStringLineSet?: RRuleStringLineSet; /** * Options to use when creating the DateRRule. */ options: DateRRuleInstanceOptions; } /** * Expansion options accepted by the static {@link DateRRuleUtility.expand} * method. Provide either a pre-built instance or parameters to build one. */ export interface DateRRuleStaticExpansionOptions extends DateRRuleExpansionOptions { /** * DateRRuleInstanceInstance to use for expansion. */ instance?: DateRRuleInstance; /** * DateRRuleInstance to build. */ instanceFrom?: MakeDateRRuleInstance; } /** * Result of expanding a recurrence rule, containing the resolved dates and * the optional range that was used to bound the expansion. */ export interface DateRRuleExpansion { /** * Range used for expansion, if applicable. */ between?: Maybe; dates: CalendarDate[]; } /** * Configuration supplied when constructing a {@link DateRRuleInstance}, * including the reference date, optional timezone, and dates to exclude. */ export interface DateRRuleInstanceOptions { /** * Start reference/date. Required if DTSTART is not provided. */ date?: CalendarDate; /** * (Optional) Timezone to use for the recurrence. * * This is not the timezone to convert values to, as this is */ timezone?: TimezoneString; /** * Dates to exclude. * * Applied AFTER {@link include}, per RFC 5545 3.8.5.1: the recurrence set is the union of the rule and the * additional dates, and only then are the exception dates subtracted. So a date present in both is * excluded. */ exclude?: DateSet; /** * Additional dates to include, beyond those the rule itself produces. Merged with any RDATE values parsed * out of the rule lines. * * These are real instants, matched and returned in the same space as {@link exclude} and as the expansion * output. */ include?: DateSet; } /** * A {@link DateRange} extended with recurrence-specific metadata, indicating * whether the recurrence runs indefinitely and when the last occurrence ends. */ export interface RecurrenceDateRange extends DateRange { /** * True if the recurrence never ends. */ forever: boolean; /** * Date the final recurrence will end at, based on the duration of the event. * * If forever, this date is undefined. */ finalRecurrenceEndsAt?: Maybe; } /** * Narrowed variant of {@link RecurrenceDateRange} for rules with no end * (`forever: true`), guaranteeing `finalRecurrenceEndsAt` is undefined. */ export interface ForeverRecurrenceDateRange extends RecurrenceDateRange { forever: true; finalRecurrenceEndsAt?: undefined; } /** * Wraps an RRule with timezone-aware date normalization so that recurrence * expansion, next-date lookups, and range checks all work correctly across * timezones. * * Use the static {@link DateRRuleInstance.make} factory or * {@link DateRRuleUtility.makeInstance} to create instances. */ export declare class DateRRuleInstance { readonly options: DateRRuleInstanceOptions; readonly rrule: DateRRule; readonly normalInstance: DateTimezoneUtcNormalInstance; /** * Factory that parses the RRule string, merges excluded dates, and builds * a fully configured instance. * * @param params - RRule source and instance options. * @returns New {@link DateRRuleInstance} bound to the parsed schedule. * @throws {Error} If neither `rruleLines` nor `rruleStringLineSet` is provided. * * @example * ```ts * const instance = DateRRuleInstance.make({ * rruleLines: 'FREQ=DAILY;COUNT=5', * options: { date: { startsAt: new Date(), duration: 3600000 }, timezone: 'America/Chicago' } * }); * ``` */ static make(params: MakeDateRRuleInstance): DateRRuleInstance; constructor(rrule: RRule, options: DateRRuleInstanceOptions); get timezone(): TimezoneString; /** * Returns the next recurrence date on or after the given reference date, * or `undefined` if the recurrence has ended. * * @param from - Reference point; defaults to now. * @returns The next occurrence date, or `undefined`. * * @example * ```ts * const next = instance.nextRecurrenceDate(new Date()); * ``` */ nextRecurrenceDate(from?: Date): Maybe; /** * Expands the recurrence rule into concrete {@link CalendarDate} instances, * optionally bounded by a date range. * * @param options - Range constraints for the expansion. * @returns Expanded dates plus the resolved range used to bound them. * @throws {Error} When the rule expands infinitely and no range is provided. * * @example * ```ts * const expansion = instance.expand({ * range: { start: new Date('2026-01-01'), end: new Date('2026-12-31') } * }); * console.log(expansion.dates.length); * ``` */ expand(options: DateRRuleExpansionOptions): DateRRuleExpansion; /** * Checks whether at least one recurrence falls within the given date range. * * @param dateRange - The range to test against. * @returns `true` if any occurrence exists within the range. */ haveRecurrenceInDateRange(dateRange: DateRange): boolean; /** * Computes the full date range spanned by this recurrence, from its first * occurrence to the end of its last occurrence (accounting for event * duration). Returns a {@link ForeverRecurrenceDateRange} when the rule * has no count or until constraint. * * @returns The recurrence date range with `forever` flag and optional `finalRecurrenceEndsAt`. */ getRecurrenceDateRange(): RecurrenceDateRange | ForeverRecurrenceDateRange; /** * Returns `true` when the underlying RRule has neither a `count` nor an * `until` constraint, meaning it recurs indefinitely. * * @returns `true` if the rule recurs indefinitely. */ hasForeverRange(): boolean; } /** * Parsed RRule options combining the separated string components with the * native `rrule` library's partial {@link Options}. */ export interface RRuleOptions extends RRuleStringSetSeparation { /** * Options for an RRule instance */ options: Partial; } /** * Stateless utility providing convenience factory and expansion methods for * {@link DateRRuleInstance}. Prefer these static methods over constructing * instances manually. */ export declare class DateRRuleUtility { /** * Expands a recurrence rule into concrete dates using either a pre-built * instance or parameters to build one on-the-fly. * * @param options - Instance (or parameters to create one) and optional range. * @returns Expansion result containing resolved dates. * @throws {Error} If neither `instance` nor `instanceFrom` is provided. * * @example * ```ts * const result = DateRRuleUtility.expand({ * instanceFrom: { * rruleLines: 'FREQ=WEEKLY;COUNT=4', * options: { date: { startsAt: new Date(), duration: 3600000 } } * }, * range: { start: new Date('2026-01-01'), end: new Date('2026-03-01') } * }); * ``` */ static expand(options: DateRRuleStaticExpansionOptions): DateRRuleExpansion; /** * Convenience alias for {@link DateRRuleInstance.make}. * * @param params - RRule source and instance options. * @returns A new {@link DateRRuleInstance}. */ static makeInstance(params: MakeDateRRuleInstance): DateRRuleInstance; /** * Parses an {@link RRuleStringLineSet} into native {@link RRuleOptions} * that can be fed into the `rrule` library. * * @param rruleStringLineSet - The raw RRule string set to parse. * @returns Parsed options including separated EXDATE and basic rule components. */ static toRRuleOptions(rruleStringLineSet: RRuleStringLineSet): RRuleOptions; }