import { DateTime, IDateAdapter } from '../date-time'; export class InvalidDateAdapterError extends Error {} const DATE_ADAPTER_ID = Symbol.for('9d2c0b75-7a72-4f24-b57f-c27e131e37b2'); export class DateAdapter implements IDateAdapter { static readonly date: unknown; static readonly hasTimezoneSupport: boolean = false; /** * Similar to `Array.isArray()`, `isInstance()` provides a surefire method * of determining if an object is a `DateAdapter` by checking against the * global symbol registry. */ static isInstance(object: unknown): object is DateAdapter { return !!(object && typeof object === 'object' && (object as any)[DATE_ADAPTER_ID]); } static isDate(_object: unknown): boolean { throw unimplementedError('isDate()'); } static fromJSON(_json: IDateAdapter.JSON): DateAdapter { throw unimplementedError('fromJSON()'); } static fromDateTime(_datetime: DateTime): DateAdapter { throw unimplementedError('fromDateTime()'); } readonly date!: unknown; readonly timezone!: string | null; /** A length of time in milliseconds */ readonly duration: number | undefined; /** * An array of OccurrenceGenerator objects which produced this DateAdapter. * * #### Details * * When a Rule object creates a DateAdapter, that Rule object adds itself to * the DateAdapter's generators property before yielding the DateAdapter. If you are using a Rule * object directly, the process ends there and the DateAdapter is yielded to you (in this case, * generators will have the type `[Rule]`) * * If you are using another object, like a Schedule however, then each DateAdapter is generated * by either a Dates (rdates) or Rule (rrule) within the Schedule. After being originally * generated by a Dates/Rule, the DateAdapter is then filtered by any exdate/exrules and, * assuming it passes, then the DateAdapter "bubbles up" to the Schedule object itself. At this * point the Schedule adds itself to the generators array of the DateAdapter and yields the date * to you. So each DateAdapter produced by a Schedule has a generators property of type * `[Schedule, Rule | Dates]`. * * The generators property pairs well with the `data` property on many OccurrenceGenerators. You * can access the OccurrenceGenerators which produced a DateAdapter via `generators`, and then * access any arbitrary data via the `data` property. * * _Note: occurrence operators are never included in the generators array._ * */ // using `unknown[]` instead of `never[]` to support convenient generator typing in `Calendar`. // If `never[]` is used, then `Calendar#schedules` *must* be typed as a tuple in order to // access any values in `generators` beyond the first (Calendar) value (the rest of the values // get typed as `never`). This would prevent passing a variable to `Calendar#schedules`. readonly generators: unknown[] = []; protected readonly [DATE_ADAPTER_ID] = true; constructor(_date: unknown, _options?: unknown) {} /** * Returns `undefined` if `this.duration` is falsey. Else returns * the `end` date. */ get end(): unknown | undefined { throw unimplementedError('end'); } set(_prop: 'timezone', _value: string | null): DateAdapter { throw unimplementedError('set()'); } valueOf(): number { throw unimplementedError('valueOf()'); } toISOString(): string { throw unimplementedError('toISOString()'); } toDateTime(): DateTime { const date = DateTime.fromJSON(this.toJSON()); date.generators.push(...this.generators); return date; } toJSON(): IDateAdapter.JSON { throw unimplementedError('toJSON()'); } assertIsValid(): boolean { throw unimplementedError('assertIsValid()'); } } function unimplementedError(name: string) { return new Error(`You must implement the "${name}" method for this DateAdapter class`); }