import { DateAdapter } from '../date-adapter'; import { DateTime } from '../date-time'; import { IOccurrenceGenerator, IRunArgs, IRunnable } from '../interfaces'; import { DateInput, dateInputToDateTime, normalizeDateTimeTimezone } from '../utilities'; const OPERATOR_ID = Symbol.for('aa6007dc-1d7f-4955-b7f1-86a226463f7e'); export abstract class Operator implements IRunnable { static isOperator(object: unknown): object is Operator { return !!(object && typeof object === 'object' && (object as any)[OPERATOR_ID]); } readonly isInfinite: boolean; readonly hasDuration: boolean; readonly timezone: string | null; /** Returns the first occurrence or, if there are no occurrences, null. */ get firstDate(): InstanceType | null { const start = this._run().next().value; if (!start) return null; return this.config.dateAdapter.fromDateTime(start) as InstanceType; } /** If generator is infinite, returns `null`. Otherwise returns the end date */ get lastDate(): InstanceType | null { if (this.isInfinite) return null; const end = this._run({ reverse: true }).next().value; if (!end) return null; return this.config.dateAdapter.fromDateTime(end) as InstanceType; } protected readonly [OPERATOR_ID] = true; constructor(readonly _streams: IOccurrenceGenerator[], protected config: IOperatorConfig) { this.timezone = config.timezone; this._streams = _streams.map(stream => stream instanceof Operator ? stream : stream.set('timezone', this.timezone), ); this.isInfinite = this.calculateIsInfinite(); this.hasDuration = this.calculateHasDuration(); } abstract set( prop: 'timezone', value: string | null, options?: { keepLocalTime?: boolean }, ): Operator; /** @internal */ abstract _run(args?: IRunArgs): IterableIterator; protected abstract calculateIsInfinite(): boolean; protected abstract calculateHasDuration(): boolean; protected normalizeDateInput(date: DateInput): DateTime; protected normalizeDateInput(date?: DateInput): undefined; protected normalizeDateInput(date?: DateInput) { if (!date) return; return dateInputToDateTime(date, this.timezone, this.config.dateAdapter); } protected normalizeRunOutput(date: DateTime) { return normalizeDateTimeTimezone(date, this.timezone, this.config.dateAdapter); } } export type OperatorFn = () => OperatorFnOutput; export type OperatorFnOutput = ( options: IOperatorConfig, ) => Operator; export interface IOperatorConfig { dateAdapter: T; timezone: string | null; base?: IRunnable; }