import { InfiniteLoopError } from '../basic-utilities'; import { DateAdapter } from '../date-adapter'; import { DateTime } from '../date-time'; import { IOccurrenceGenerator } from '../interfaces'; import { IRunArgs } from '../interfaces/runnable'; import { DateInput } from '../utilities'; export class OccurrenceIterator< T extends typeof DateAdapter, G extends ReadonlyArray> = ReadonlyArray> > { private readonly iterator: IterableIterator; private readonly isInfinite: boolean; constructor(private iterable: IOccurrenceGenerator, private args: IRunArgs) { this.iterator = iterable._run(args); this.isInfinite = iterable.isInfinite; } [Symbol.iterator] = () => this._run(); next(args?: { skipToDate?: DateInput }) { return this._run(args).next(); } toArray() { if (this.args.end || this.args.take || !this.isInfinite) { return Array.from(this._run()); } throw new InfiniteLoopError( 'OccurrenceIterator#toArray() can only be called if the iterator ' + 'is not infinite, or you provide and `end` argument, or you provide ' + 'a `take` argument.', ); } private *_run(rawArgs?: { skipToDate?: DateInput }) { let args = this.normalizeRunArgs(rawArgs); let date = this.iterator.next(args).value; while (date) { const yieldArgs = yield this.normalizeDateOutput(date); args = this.normalizeRunArgs(yieldArgs); date = this.iterator.next(args).value; } } private normalizeRunArgs(args?: { skipToDate?: DateInput }) { return { skipToDate: this.normalizeDateInput(args && args.skipToDate), }; } private normalizeDateInput(date?: DateInput) { if (!date) { return; } return DateAdapter.isInstance(date) ? date.set('timezone', this.iterable.timezone).toDateTime() : new this.iterable.dateAdapter(date).set('timezone', this.iterable.timezone).toDateTime(); } private normalizeDateOutput(date: DateTime): InstanceType & { generators: G }; private normalizeDateOutput(date?: DateTime): undefined; private normalizeDateOutput(date?: DateTime) { if (!date) { return; } return this.iterable.dateAdapter.fromDateTime(date) as InstanceType; } } export interface IOccurrencesArgs { start?: DateInput; end?: DateInput; take?: number; reverse?: boolean; }